显示锁Lock和ReentrantLock
Lock 是一个接口,提供了无条件的、可轮询的、定时的、可中断的锁获取操作,所有加锁和解锁的方法都是显示的。核心方法有lock()、unlock()、tryLock(),实现类有ReentrantLock、ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock
void lock()
拿不到lock就不罢休,不然线程就一直block,调用方法结束后,要是用unlock,否则会造成死锁
代码结构示例:
public void m(){
lock.lock();
try {
} catch (Exception e) {
// TODO: handle exception
}finally{
lock.unlock();
}
}
boolean tryLock()
马上返回,拿到lock就返回true,不然返回false;通常对于那种不必获取锁的操作可能有用,注意必须拿到锁的方法才可调用unlock()方法
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
ReentrantLock lock = new ReentrantLock();
public void tryLockTest(){
try {
boolean getLock = lock.tryLock();
if(getLock){
System.out.println("Thead----"+Thread.currentThread().getName()+"---get lock---");
Thread.sleep(10);
lock.unlock();//必须拿到锁的线程才可调用此方法,否则抛异常
}else{
System.out.println("Thead----"+Thread.currentThread().getName()+"---not get lock---");
Thread.sleep(10);
}
}catch(Exception e){
System.out.println(Thread.currentThread().getName()+"异常");
e.printStackTrace();
}
}
}
运行结果:
由结果可以看出,只有第一个线程获取到锁。
boolean tryLock(long ParamLong,TimeUnit ParamTimeUnit) throws InterruptedException
带时间限制的tryLock(),拿不到lock,就等一段时间,超时返回false
图中画红框部分是经修改的代码,修改后的执行结果如下
当线程没有拿到lock,要等一会,超时后仍没有拿到,才会返回false
void lockInterruptibly() throws InterruptedException
优先考虑响应中断,而不是响应锁定的普通获取,当外部线程被Interrupted,则当线程调用lockInterruptibly时进入catch方法中,若外部线程没有被打断,则与功能与调用lock方法一致
代码进行如下修改
子方法中调用lockInterruptibly()
主方法中,将一些线程打断
下面我们看一下执行结果
Lock与synchronized比较
1、lock使用起来更加灵活,但是必须有释放锁的动作配合
2、lock适用于代码块,而synchronized是对象之间的互斥锁
注意以下两种方式的区别
第一种方式:两个方法之间的锁是独立的
public class MainT {
/**
* @param args
*/
public static void main(String[] args) {
final LockTest lt = new LockTest();
//final LockTest lt2 = new LockTest();
// TODO Auto-generated method stub
for(int i=0;i<2;i++){
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
lt.get();
}
});
t1.start();
}
for(int i=0;i<2;i++){
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
lt.put();
}
});
t1.start();
}
}
}
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
public void get(){
ReentrantLock lock = new ReentrantLock();
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"----get begin---");
Thread.sleep(1000);//模仿干活
System.out.println(Thread.currentThread().getName()+"----get end---");
lock.unlock();
} catch (Exception e) {
// TODO: handle exception
}
}
public void put(){
ReentrantLock lock = new ReentrantLock();
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"----put begin---");
Thread.sleep(1000);//模仿干活
System.out.println(Thread.currentThread().getName()+"----put end---");
lock.unlock();
} catch (Exception e) {
// TODO: handle exception
}
}
}
每个调用此方法的锁都是独立的,没有起到锁的用途
第二种方式:两个方法之间使用相同的锁
/**
* @param args
*/
public static void main(String[] args) {
final LockTest lt = new LockTest();
// TODO Auto-generated method stub
for(int i=0;i<2;i++){
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
lt.get();
}
});
t1.start();
}
for(int i=0;i<2;i++){
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
lt.put();
}
});
t1.start();
}
}
}
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
ReentrantLock lock = new ReentrantLock();
public void get(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"----get begin---");
Thread.sleep(1000);//模仿干活
System.out.println(Thread.currentThread().getName()+"----get end---");
lock.unlock();
} catch (Exception e) {
// TODO: handle exception
}
}
public void put(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"----put begin---");
Thread.sleep(1000);//模仿干活
System.out.println(Thread.currentThread().getName()+"----put end---");
lock.unlock();
} catch (Exception e) {
// TODO: handle exception
}
}
}
两个线程调用方法使用的同一个锁,所以串行执行;结果如下图所示