Lock锁
开始我比较喜欢使用synchronize关键字来实现线程的同步机制,因为他的使用方法很简单,不用考录很多的细节,对于初级程序猿来说,要求更低,
现在来介绍我刚学到的另外一种,通过Lock 锁来实现同步的方法,
Lock锁优点:能够使程序并发更加高效
缺点:对程序猿的要求更高
Lock中的方法
public interface Lock { void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); Condition newCondition(); }
从Lock源码中可以看出,它是一个接口
1)lock():如果能获取锁就返回,如果不能获取,则一直等待获取锁
2)lockinterruptidly():支持线程中断,如果线程中断,则默认他不会去竞争,这个相对于同步代码块和同步方法而言,可扩展性大了很多
3)trylock():如果能获取锁就立刻返回true 否则返回false
4)trylock(ling time,TimeUnit unit)如果能获取锁则返回true 如果有一下两种情况,则返回false
线程被中断了
时间到了
5)unlock()释放一个锁
6)Condition newCondition()引入 condition有两个方法意图
a.对一个共享资源有读和写的能力,如果读线程或写线程获取了Lock的权力,即有能力进入,但是如果里面没有内容,读也没有用,如果空间已满了,写也写不了,所以还得有条件去判断一下,是不是线程要等待了;
b.提供一种多线程之间的通信机制,类似wait()和nofity()的原理。
锁的相关概念介绍
1.可重入锁
也叫递归锁,指同一线程外层函数获得该锁以后,内层递归函数仍有获取该锁的代码,但不受影响,
在Java环境下,ReetrantLock和synchronize都是可重入锁,最大的作用是避免死锁
lass MyClass { public synchronized void method1() { method2(); } public synchronized void method2() { } }
在一个线程获得method1方法的锁后,进入method1,同样被synchronized修饰的method2方法就不需要再次去获取锁了。因为synchronized具有可重入性,所以进入直接运行
2.可中断锁
在Java中,synchronized就不是可中断锁,而Lock是可中断锁,这也是我们需要Lock实现同步的重要原因。
如果某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,想先处理其他事情,我们可以让它中断自己或者在别的线程中中断它,这种就是可中断锁。
在前面Lock的接口方法lockInterruptibly()的用法时已经体现了Lock的可中断性。
3.公平锁
公平锁即尽量以请求锁的顺序来获取锁。比如同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。
非公平锁即无法保证锁的获取是按照请求锁的顺序进行的。这样就可能导致某个或者一些线程永远获取不到锁。
在Java中,synchronized就是非公平锁,它无法保证等待的线程获取锁的顺序。
而对于ReentrantLock和ReentrantReadWriteLock,它默认情况下是非公平锁,但是可以设置为公平锁。
下附老师的我爱你程序源码
package com.cmy.Lock.demo3; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * lock实现案例:线程A 线程B 线程C 打印 10次 '我爱你' * * 案例思路:使用一个ReentranLock 对象 * 2个Condition对象 和synchronize(){}+wait()+notify()大致相仿 */ public class LockConditionDemoWord implements Runnable{ // 打印次数 private static final int PRINT_COUNT = 10; // 打印锁 private final ReentrantLock reentrantLock; // 本线程打印所需的condition private final Condition thisCondtion; // 下一个线程打印所需要的condition private final Condition nextCondtion; // 打印字符 private final String printChar; public LockConditionDemoWord(ReentrantLock reentrantLock, Condition thisCondtion, Condition nextCondition, String printChar) { this.reentrantLock = reentrantLock; this.nextCondtion = nextCondition; this.thisCondtion = thisCondtion; this.printChar = printChar; } @Override public void run() { // 获取打印锁 进入临界区 reentrantLock.lock(); try { // 连续打印PRINT_COUNT次 for (int i = 0; i < PRINT_COUNT; i++) { //打印字符 System.out.print(printChar); // 使用nextCondition唤醒下一个线程 // 因为只有一个线程在等待,所以signal或者signalAll都可以 nextCondtion.signal(); // 不是最后一次则通过thisCondtion等待被唤醒 // 必须要加判断,不然虽然能够打印10次,但10次后就会直接死锁 if (i < PRINT_COUNT - 1) { try { // 本线程让出锁并等待唤醒 thisCondtion.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } } finally { // 释放打印锁 reentrantLock.unlock(); } } public static void main(String[] args) throws InterruptedException { // 写锁 ReentrantLock lock = new ReentrantLock(); // 打印a线程的condition Condition conditionA = lock.newCondition(); // 打印b线程的condition Condition conditionB = lock.newCondition(); // 打印c线程的condition Condition conditionC = lock.newCondition(); // 实例化A线程 Thread printerA = new Thread(new LockConditionDemoWord(lock, conditionA, conditionB, "我")); // 实例化B线程 Thread printerB = new Thread(new LockConditionDemoWord(lock, conditionB, conditionC, "爱")); // 实例化C线程 Thread printerC = new Thread(new LockConditionDemoWord(lock, conditionC, conditionA, "你")); // 依次开始A B C线程 printerA.start(); Thread.sleep(100); printerB.start(); Thread.sleep(100); printerC.start(); } }