目录
1.介绍Lock
2.Lock的基本使用
3.Lock之线程之间的通信
4.总结
一、介绍Lock
首先先讲一下笔者为什么会涉及到Lock这个东西,使用synchronized来锁对象或方法时,如果被锁的这个方法发生阻塞(sleep),那么将影响锁资源的释放,
而其他处于等待状态的对象或方法将一直处于等待状态,直到休眠完或阻塞清除,这就带来了一大并发症。而使用Lock则可以解决这一问题。
Lock与synchronized之间有很多差异:
1.Lock是一个接口,synchronized则是java中的一个关键字
2.Lock需要手动释放锁,synchronized不需要手动释放锁
二、Lock的基本使用
Lock的API
Lock是一个接口,他需要由ReentrantLock、ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock来创建
它主要的方法有:
ReentrantWriteReadLock是读写锁,它将文件的读和写分开,在这不多做研究。
如想了解的读者请参考https://blog.csdn.net/zhuhezan/article/details/6613108
以下是Lock的基本使用:
package com.demo.thread; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockThread { //创建锁对象 Lock lock = new ReentrantLock(); public void lock(String name) { // 获取锁 lock.lock(); try { System.out.println(name + "获取锁"); // 访问此锁保护的资源 } finally { // 释放锁 lock.unlock(); System.out.println(name + "释放锁"); } } public static void main(String[] args) { LockThread lt = new LockThread(); new Thread(() -> lt.lock("A")).start(); new Thread(() -> lt.lock("B")).start(); } }
三、Lock之线程之间的通信
如果我们不使用Lock,要做到线程之间的通信我们需要使用到Object类中的wait、notify、notifyAll方法来控制线程间的通信。在jdk1.5当中,线程之间的通信如果使用Lock接口的话需要使用到newCondition方法来创建需要通信的对象Condition。
一下是newCondition方法的具体解释:
Condition对象的方法如下:
一下是使用condition完成Lock对象线程间的通信Demo:
package com.demo.condition; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Condition初次使用 * 使用Condition控制线程间的通信 * @author Administrator * */ public class ConditionDemo { public static void main(String[] args) { Output output = new Output(); for(int i =0;i<2;i++){ new Thread(new Runnable() { public void run() { output.get1(1); } }).start(); new Thread(new Runnable() { public void run() { output.get2(2); } }).start(); new Thread(new Runnable() { public void run() { output.get3(3); } }).start(); } } } class Output{ private int count =1; //创建Lock对象 final Lock lock = new ReentrantLock(); //创建三个condition对象 private Condition condition1 = lock.newCondition(); private Condition condition2 = lock.newCondition(); private Condition condition3 = lock.newCondition(); public void get1(int i){ //获取锁资源 lock.lock(); System.out.println("condition1已获取锁资源"); try { while(count!=1){ condition1.await(); } System.out.println("condition1获取到资源"); for(int j=0;j<10;j++){ System.out.println(i+"正在执行condition1"+j); Thread.sleep(1000); } count++; //唤醒第二个等待的线程 condition2.signal(); } catch (InterruptedException e) { e.printStackTrace(); }finally{ //释放锁资源,避免锁死状态 lock.unlock(); } } public void get2(int i){ //获取锁资源 lock.lock(); System.out.println("condition2已获取锁资源"); try { while(count!=2){ condition2.await(); } System.out.println("condition2获取到资源"); for(int j=0;j<10;j++){ System.out.println(i+"正在执行condition2"+j); Thread.sleep(1000); } count++; //唤醒第三个等待的线程 condition3.signal(); } catch (InterruptedException e) { e.printStackTrace(); }finally{ //释放锁资源,避免锁死状态 lock.unlock(); } } public void get3(int i){ //获取锁资源 lock.lock(); System.out.println("condition3已获取锁资源"); try { while(count!=3){ condition3.await(); } System.out.println("condition3获取到资源"); for(int j=0;j<10;j++){ System.out.println(i+"正在执行condition3"+j); Thread.sleep(1000); } count=1; //唤醒第一个等待的线程 condition1.signal(); } catch (InterruptedException e) { e.printStackTrace(); }finally{ //释放锁资源,避免锁死状态 lock.unlock(); } } }
四、总结
结合以上观点来看,总而言之,使用Lock相对于传统使用synchronized关键字来说,逻辑更清晰,避免了线程等待的并发症。而且
我们还可以直观的观测到线程之间或去锁的状态。个人还是推荐是用Lock代替synchronized的。