好运10分快3官网_Java多线程,对锁机制的进一步分析

  • 时间:
  • 浏览:0

1 可重入锁

    可重入锁,也叫递归锁。它有两层含义,第一,当另三个多多多线程 在外层函数得到可重入锁后,能直接递归地调用该函数,第二,同一多多线程 在外层函数获得可重入锁后,内层函数能不能直接获取该锁对应其它代码的控制权。之前 让我们歌词 歌词 歌词 提到的synchronized和ReentrantLock也有可重入锁。

    通过ReEnterSyncDemo.java,让我们歌词 歌词 歌词 来演示下synchronized关键字的可重入性。    

1	class SyncReEnter implements Runnable{
2	   public synchronized void get(){
3	     System.out.print(Thread.currentThread().getId() + "\t");
4	      //在get土办法

里调用set
5	      set();
6	    }
7	    public synchronized void set()
8	    {System.out.print(Thread.currentThread().getId()+"\t"); }
9	    public void run() //run土办法

里调用了get土办法

10	    { get();}
11	}
12	public class ReEnterSyncDemo {
13	    public static void main(String[] args) {
14	       	SyncReEnter demo=new SyncReEnter();
15	        new Thread(demo).start();
16	        new Thread(demo).start();
17	    }
18	}

    在第1行里,让我们歌词 歌词 歌词 是让syncReEnter类通过实现Runnable的土办法 来实现多多多线程 ,在其中第2和第7行所定义的get和set土办法 均含高synchronized关键字。在第9行定义的run土办法 里,让我们歌词 歌词 歌词 调用了get土办法 。在main函数的第15和16行里,让我们歌词 歌词 歌词 启动了2次多多线程 ,这段代码的输出如下。

    8   8   9   9  

    在第15行第一次启动多多线程 时,在run土办法 里,会调用含高synchronized关键字的get土办法 ,这时你这个多多线程 会得到get土办法 的锁,当执行到get里的set土办法 时,肯能set土办法 也含高synchronized关键字,之前 set是含高在get里的,一点一点这里不想再次申请set的锁,能继续执行,一点一点通过输出,让我们歌词 歌词 歌词 能看一遍get和set的打印语录是连续输出的。同理让我们歌词 歌词 歌词 能理解第16行第二次启动多多线程 的输出。

    通过ReEnterLock.java,让我们歌词 歌词 歌词 来演示下ReentrantLock的可重入性。      

1	import java.util.concurrent.locks.ReentrantLock;
2	class LockReEnter implements Runnable {
3		ReentrantLock lock = new ReentrantLock();
4		public void get() {
5		  lock.lock();
6	  	  System.out.print(Thread.currentThread().getId()+"\t");
7		  // 在get土办法

里调用set
8		  set();
9		  lock.unlock();
10	   }
11	   public void set() {
12		lock.lock();
13		System.out.print(Thread.currentThread().getId() + "\t");
14		lock.unlock();
15	   }
16	   public void run() 
17	   { get(); }
18	}
19	public class ReEnterLock {
20		public static void main(String[] args) {
21			LockReEnter demo = new LockReEnter();
22			new Thread(demo).start();
23			new Thread(demo).start();
24		}
25	}

    在第2行创建的LockReEnter类里,让我们歌词 歌词 歌词 同样含高了get和set土办法 ,并在get土办法 里调用了set土办法 ,只不过在get和set土办法 里,让我们歌词 歌词 歌词 也有用synchronized,一点一点我用第3行定义的ReentrantLock类型的lock对象来管理多多多线程 的并发,在第16行的run土办法 里,让我们歌词 歌词 歌词 同样地调用了get土办法 。

    在main函数里,让我们歌词 歌词 歌词 同样地在第22和23行里启动了两次多多线程 ,这段代码的运行结果如下。

    8   8   9   9

    当在第22行里第一次启动LockReEnter类型的多多线程 后,在调用get土办法 时,能得到第5行的锁对象,get土办法 会调用set土办法 ,虽然set土办法 里的第12行会再次申请锁,但肯能LockReEnter多多线程 在get土办法 里肯能得到了锁,一点一点在set土办法 里不能不能得到锁,一点一点第一次运行时,get和set土办法 会一块儿执行,同样地,在第23行第二次其中多多线程 时,也会一块儿打印get和set土办法 里的输出。

    在项目的一点场景里,另三个多多多线程 有肯能须要多次进入被锁关联的土办法 ,比如某数据库的操作的多多线程 须要多次调用被锁管理的“获取数据库连接”的土办法 ,这时,肯能使用可重入锁就能防止死锁的疑问,相反,肯能让我们歌词 歌词 歌词 也有用可重入锁,没法在第二次调用“获取数据库连接”土办法 时,也有肯能被锁住,从而原困死锁疑问。

2 公平锁和非公平锁

    在创建Semaphore对象时,让我们歌词 歌词 歌词 能不能通过第另三个多参数,来指定该Semaphore对象算不算以公平锁的土办法 来调度资源。

    公平锁会维护另三个多等待图片队列,多个在阻塞状况等待图片的多多线程 会被插入到你这个等待图片队列,在调度时是按它们所发请求的时间顺序获取锁,而对于非公平锁,当另三个多多多线程 请求非公平锁时,肯能此时该锁变成可用状况,没法你这个多多线程 会跳过等待图片队列中所有的等待图片多多线程 而获得锁。

    让我们歌词 歌词 歌词 在创建可重入锁时,也能不能通过调用带布尔类型参数的构造函数来指定该锁算不算公平锁。ReentrantLock(boolean fair)。

    在项目里,肯能请求锁的平均时间间隔较长,建议使用公平锁,反之建议使用非公平锁。

    比如有个服务窗口,肯能采用非公平锁的土办法 ,当窗口空闲时,也有让下一号来,一点一点我假如来人就服务,另三个多多能缩短窗口的空闲等待图片时间,从而提升单位时间内的服务数量(也一点一点我吞吐量)。相反,肯能这是个比较冷门的服务窗口,在一点一点时间里来请求服务的频次也有就是高,比如一小时才来另三个多人,没法就能不能选折 公平锁了。肯能,肯能要缩短用户的平均等待图片时间,没法能不能选折 公平锁,另三个多多就能防止“早到的请求晚防止“的状况。

3 读写锁

    之前 让我们歌词 歌词 歌词 通过synchronized和ReentrantLock来管理临界资源时,只一点一点我另三个多多多线程 得到锁,其它多多线程 能不能了操作你这个临界资源,你这个锁能不能叫做“互斥锁”。

    和你这个管理土办法 相比,ReentrantReadWriteLock对象会使用两把锁来管理临界资源,另三个多是“读锁“,另三个多多是“写锁“。

    肯能另三个多多多线程 获得了某资源上的“读锁“,没法其它对该资源执行“读操作“的多多线程 还是能不能继续获得该锁,也一点一点我说,“读操作“能不能并发执行,但执行“写操作“的多多线程 会被阻塞。肯能另三个多多多线程 获得了某资源的“写锁“,没法其它任何企图获得该资源“读锁“和“写锁“的多多线程 都将被阻塞。

    和互斥锁相比,读写锁在保证并发时数据准确性的一块儿,允一点个多多线程 一块儿“读“某资源,从而能提升下行时延 。通过下面的ReadWriteLockDemo.java,让我们歌词 歌词 歌词 来观察下通过读写锁管理读写并发多多线程 的土办法 。    

1	import java.util.concurrent.locks.Lock;
2	import java.util.concurrent.locks.ReentrantReadWriteLock;
3	class ReadWriteTool {
4		private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
5		private Lock readLock = lock.readLock();
6		private Lock writeLock = lock.writeLock();
7		private int num = 0;
8	  	public void read() {//读的土办法

 
9			int cnt = 0;
10			while (cnt++ < 3) {
11				try {
12					readLock.lock();				System.out.println(Thread.currentThread().getId()
13							+ " start to read");
14					Thread.sleep(100);		
15		System.out.println(Thread.currentThread().getId() + " reading,"	+ num);
16				} catch (Exception e) 
17	            { e.printStackTrace();}
18	            finally { readLock.unlock(); 	}
19			}
20		}
21		public void write() {//写的土办法

22			int cnt = 0;
23			while (cnt++ < 3) {
24				try {
25					writeLock.lock();		
26			System.out.println(Thread.currentThread().getId()
27							+ " start to write");
28					Thread.sleep(100);
29					num = (int) (Math.random() * 10);
100				System.out.println(Thread.currentThread().getId() + " write," + num);
31				} catch (Exception e) 
32	            { e.printStackTrace();} 
33	            finally { writeLock.unlock();}
34			}
35		}
36	}

    在第3行定义的ReadWriteTool 类里,让我们歌词 歌词 歌词 在第4行创建了另三个多读写锁,并在第5和第6行,分别通过你这个读写锁的readLock和writeLock土办法 ,分别创建了读锁和写锁。

    在第8行的read土办法 里,让我们歌词 歌词 歌词 是先通过第12行的代码加“读锁“,之前 在第15行进行读操作。在第21行的write土办法 里,让我们歌词 歌词 歌词 是先通过第25行的代码加“写锁”,之前 在第100行进行写操作。    

37	class ReadThread extends Thread {
38		private ReadWriteTool readTool;
39		public ReadThread(ReadWriteTool readTool) 
40	    { this.readTool = readTool;	}
41		public void run() 
42	    { readTool.read();}
43	}
44	class WriteThread extends Thread {
45		private ReadWriteTool writeTool;
46		public WriteThread(ReadWriteTool writeTool) 
47	    { this.writeTool = writeTool; }
48		public void run() 
49	    { writeTool.write();	}
100	}

    在第37行和第44行里,让我们歌词 歌词 歌词 分别定义了读和写这另三个多多多线程 ,在ReadThread多多线程 的run土办法 里,让我们歌词 歌词 歌词 调用了ReadWriteTool类的read土办法 ,而在WriteThread多多线程 的run土办法 里,则调用了write土办法 。    

51	public class ReadWriteLockDemo {
52		public static void main(String[] args) {
53			ReadWriteTool tool = new ReadWriteTool();
54			for (int i = 0; i < 3; i++) {
55				new ReadThread(tool).start();
56				new WriteThread(tool).start();
57			}
58		}
59	}

    在main函数的第53行,让我们歌词 歌词 歌词 创建了另三个多ReadWriteTool类型的tool对象,在第55和56行初始化读写多多线程 时,让我们歌词 歌词 歌词 传入了该tool对象,也一点一点我说,通过54行for循环创建并启动的多个读写多多线程 是通过同另三个多读写锁来控制读写并发操作的。

    出于多多多线程 并发调度的原困,让我们歌词 歌词 歌词 每次运行都肯能得到不同的结果,但从那先 不同的结果里,让我们歌词 歌词 歌词 都態明显地看出读写锁协调管理读写多多线程 的土办法 ,比如来看下如下的每种输出结果。    

1	8 start to read
2	10 start to read
3	12 start to read
4	8 reading,0
5	10 reading,0
6	12 reading,0
7	9 start to write
8	9 write,2
9	11 start to write
10	11 write,6

    这里让我们歌词 歌词 歌词 是通过ReadWriteTool类里的读写锁管理其中的num值,从第1到第6行的输出中让我们歌词 歌词 歌词 能看一遍,虽然8号多多线程 肯能得到读锁之前 之前 开始读num资源时,10号和12号读多多线程 依然能不能得到读锁,从而能并发地读取num资源。但在读操作期间,是不允许有写操作的多多线程 进入,也一点一点我说,当num资源上有读锁期间,其它多多线程 是无法得到该资源上的“写锁”的。

    从第7到第10行的输出中让我们歌词 歌词 歌词 能看一遍,当9号多多线程 得到num资源上的“写锁”时,其它多多线程 是无法得到该资源上的“读锁“和“写锁“的,而11号多多线程 一定得当9号多多线程 释放了“写锁”后,不能不能得到num资源的“写锁”。

    肯能在项目里对一点资源(比如文件)有读写操作,这时让我们歌词 歌词 歌词 不妨能不能使用读写锁,肯能读操作的数量要远超过写操作时,没法更能不能用读写锁来让读操作能不能并发执行,从而提升性能。