目录
1.介绍Lock
2.Lock的基本使用
3.Lock之线程之间的通信
4.总结
一、介绍Lock
首先先讲一下笔者为什么会涉及到Lock这个东西,使用synchronized来锁对象或方法时,如果被锁的这个方法发生阻塞(sleep),那么将影响锁资源的释放,
而其他处于等待状态的对象或方法将一直处于等待状态,直到休眠完或阻塞清除,这就带来了一大并发症。而使用Lock则可以解决这一问题。
Lock与synchronized之间有很多差异:
1.Lock是一个接口,synchronized则是java中的一个关键字
2.Lock需要手动释放锁,synchronized不需要手动释放锁
二、Lock的基本使用
Lock的API
ReentrantLock、ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock来创建
它主要的方法有:
ReentrantWriteReadLock是读写锁,它将文件的读和写分开,在这不多做研究。
如想了解的读者请参考
以下是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的。