1.Reentrantlock是手动锁,重入锁,可以来代替synchronized
synchronized的使用方法如下:
public class T(){
public synchronized void m1(){
//
}
public synchronized void m2(){
//
}
public static void main(String[] args){
T t=new T();
new Thread(t::m1).start();
new Thread(t::m2).start();
//程序在执行过程中,第一个线程得到了t的锁,第二个线程执行时,也想得到t的锁。只能等第一个线程将锁释放。
}
}
用Reentrantlock代替synchronized,用法如下,千万注意:手动上锁,必须手动解锁。
Lock lock = new Reentrantlock();//首先实例化一个锁lock
public void m1(){
lock.lock();//手动上锁,相当于synchronized(this)
try{
//上锁之后执行线程内容
//~~~~
}catch(InterruptedException e){
e.printStrackTrace;
}finally{
//手动锁最重要的是必须手动释放锁
//与synchronized不同的是,sync出现异常,默认自动释放锁。而Reentrantlock必须手动释放。
lock.unlock();
}
}
//Reentrantlock必须有finally释放锁
public void m2(){
lock.lock();//手动上锁,相当于synchronized(this)
try{
//上锁之后执行线程内容
//~~~~
}catch(InterruptedException e){//延时的时候可能出现的异常
e.printStrackTrace;
}finally{
lock.unlock();
}
}
//如果想让两个方法互斥的话,锁定同一把锁就好了
2.与sync不同的是,Reentrantlock可以尝试上锁
synchronized上锁是同步方法没有执行完的时候,其他线程想执行这段同步方法必须一直等待锁的释放。
而Reentrantlock可以尝试上锁,如果在一定时间内都没有申请到锁,那么选择等待或执行其他任务。Reentrantlock有更多的选择。
示例代码:
public class ReLockTest {
Lock lock =new ReentrantLock();
public void m1(){
try {
lock.lock();
System.out.println("m1 start");
for(int i=0;i<6;i++){
System.out.println("add"+i);
TimeUnit.SECONDS.sleep(1);
}
System.out.println("m1 end");
}catch(InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void m2(){
try{
boolean isLOCK=lock.tryLock();//先尝试能否得到锁
System.out.println("isLOCK:"+isLOCK);//isLOCK:false
TimeUnit.SECONDS.sleep(10);//10s之后再尝试
isLOCK=lock.tryLock();
System.out.println("isLoCK:"+isLOCK);//isLoCK:true
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
public static void main(String[] args) {
ReLockTest r1=new ReLockTest();
new Thread(r1::m1).start();
new Thread(r1::m2).start();
}
}
并且trylock可以设定申请锁的时限,比如:
//改进代码,trylock可以设置try时间(时间长度,时间单位)
public void m2(){
boolean isLOCK=false;
try{
isLOCK=lock.tryLock(10,TimeUnit.SECONDS);
System.out.println("isLOCK:"+isLOCK);
}catch(InterruptedException e){
e.printStackTrace();
}finally{
if(isLOCK)lock.unlock();//要注意trylock释放锁的时候,如果申请到了锁,再释放锁。
}
}
trylock为true指的是,刚刚获取到锁,或已经占有了锁
3.可以用lockInterruptibly()设定锁是可以打断的
补充一个m3方法如下:
public void m3(){
try{
System.out.println("this is m3"+lock.tryLock());//false,说明一开始线程2没有申请到锁
lock.lockInterruptibly();//对interrupt()方法做出响应,会抛出异常被catch,后面的代码不执行。
System.out.println("this is m3"+lock.tryLock());
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
}catch(InterruptedException e){
System.out.println("m3 interrupted");
}finally {
//lockInterruptibly()方法不确定能不能申请到锁。
//所以要释放锁的时候先判断有没有申请到锁
if(lock.tryLock())lock.unlock();
}
}
public static void main(String[] args) {
ReLockTest r1=new ReLockTest();
//在main函数里面,开启线程1,获得锁。
new Thread(r1::m1).start();
//如果开启线程2,是申请不到锁的。
Thread t2=new Thread(r1::m3);
t2.start();
try{
//主线程延时5秒钟之后,将t2线程打断
TimeUnit.SECONDS.sleep(5);
}catch(InterruptedException e){
e.printStackTrace();
}
t2.interrupt();
}
执行结果为:
m1 start
add0
this is m3false
add1
add2
add3
add4
m3 interrupted//这里可以看到线程1在执行的过程中,线程2申请锁,失败,延时之后,线程2 被打断
add5
m1 end
Reentrantlock还可以作为公平锁
public static Lock lock=new Reentrantlock(true);//当加上参数true的时候,指定是公平锁。
Reentrantlock还可以指定为公平锁。synchtonized默认是非公平锁。也就是说,当一个线程释放锁之后,其他的线程哪个先得到锁是不确定的。
公平锁会根据等待时间,让等待时间更久的得到这把锁。但是公平锁效率比较低。