幸运时时彩注册网址_Java多线程,对锁机制的进一步分析

  • 时间:
  • 浏览:1
  • 来源:QQ猎鹰乐园_提供QQ思维国际技术_小磊资源网资讯

1 可重入锁

    可重入锁,也叫递归锁。它有两层含义,第一,当十2个 任务管理器在外层函数得到可重入锁后,能直接递归地调用该函数,第二,同一任务管理器在外层函数获得可重入锁后,内层函数不用 直接获取该锁对应其它代码的控制权。以后亲戚亲戚朋友 提到的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个 任务管理器有不可能 如此 多次进入被锁关联的妙招,比如某数据库的操作的任务管理器如此 多次调用被锁管理的“获取数据库连接”的妙招,这时,不可能 使用可重入锁就能避免死锁的问提,相反,不可能 亲戚亲戚朋友 全是 用可重入锁,如此 在第二次调用“获取数据库连接”妙招时,全是 不可能 被锁住,从而原困死锁问提。

2 公平锁和非公平锁

    在创建Semaphore对象时,亲戚亲戚朋友 不用 通过第十2个 参数,来指定该Semaphore对象算是以公平锁的妙招来调度资源。

    公平锁会维护十2个 听候队列,多个在阻塞清况 听候的任务管理器会被插入到四种 听候队列,在调度时是按它们所发请求的时间顺序获取锁,而对于非公平锁,当十2个 任务管理器请求非公平锁时,不可能 此时该锁变成可用清况 ,如此 四种 任务管理器会跳过听候队列中所有的听候任务管理器而获得锁。

    亲戚亲戚朋友 在创建可重入锁时,不用 能通过调用带布尔类型参数的构造函数来指定该锁算是公平锁。ReentrantLock(boolean fair)。

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

    比如有个服务窗口,不可能 采用非公平锁的妙招,当窗口空闲时,全是 让下一号来,好多好多 我希望来人就服务,如此 能缩短窗口的空闲听候时间,从而提升单位时间内的服务数量(也好多好多 吞吐量)。相反,不可能 这是个比较冷门的服务窗口,在好多好多 时间里来请求服务的频次全是以后高,比如一小时才来十2个 人,如此 就不用 取舍 公平锁了。不可能 ,不可能 要缩短用户的平均听候时间,如此 不用 取舍 公平锁,如此 就能避免“早到的请求晚避免“的清况 。

3 读写锁

    以后亲戚亲戚朋友 通过synchronized和ReentrantLock来管理临界资源时,只好多好多 十2个 任务管理器得到锁,其它任务管理器如此 操作四种 临界资源,四种 锁不用 叫做“互斥锁”。

    和四种 管理妙招相比,ReentrantReadWriteLock对象会使用两把锁来管理临界资源,十2个 是“读锁“,如此 是“写锁“。

    不可能 十2个 任务管理器获得了某资源上的“读锁“,如此 其它对该资源执行“读操作“的任务管理器还是不用 继续获得该锁,也好多好多 说,“读操作“不用 并发执行,但执行“写操作“的任务管理器会被阻塞。不可能 十2个 任务管理器获得了某资源的“写锁“,如此 其它任何企图获得该资源“读锁“和“写锁“的任务管理器都将被阻塞。

    和互斥锁相比,读写锁在保证并发时数据准确性的一齐,允许多个任务管理器一齐“读“某资源,从而能提升传输效率。通过下面的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(50000);		
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(50000);
29					num = (int) (Math.random() * 10);
500				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行创建了十2个 读写锁,并在第5和第6行,分别通过四种 读写锁的readLock和writeLock妙招,分别创建了读锁和写锁。

    在第8行的read妙招里,亲戚亲戚朋友 是先通过第12行的代码加“读锁“,以后在第15行进行读操作。在第21行的write妙招里,亲戚亲戚朋友 是先通过第25行的代码加“写锁”,以后在第500行进行写操作。    

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();	}
500	}

    在第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行,亲戚亲戚朋友 创建了十2个 ReadWriteTool类型的tool对象,在第55和56行初始化读写任务管理器时,亲戚亲戚朋友 传入了该tool对象,也好多好多 说,通过54行for循环创建并启动的多个读写任务管理器是通过同十2个 读写锁来控制读写并发操作的。

    出于多任务管理器并发调度的原困,亲戚亲戚朋友 每次运行全是 可能 得到不同的结果,但从那先 不同的结果里,亲戚亲戚朋友 都態明显地看出读写锁协调管理读写任务管理器的妙招,比如来看下如下的次要输出结果。    

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资源的“写锁”。

    不可能 在项目里对许多资源(比如文件)有读写操作,这时亲戚亲戚朋友 不妨不用 使用读写锁,不可能 读操作的数量要远超过写操作时,如此 更不用 用读写锁来让读操作不用 并发执行,从而提升性能。