一、ReentrantLock
1.1、reentrantlock用于替代synchronized
synchronized手动上锁,自动释放
reentrantlock手动上锁,手动释放
注意: ReentrantLock是手动锁,执行结束必须要必须要必须要手动释放锁。遇到异常,jvm会自动释放锁,但是lock必须手动释放锁,因此经常在finally中进行锁的释放
public class MyReentrantLock1 {
Lock lock = new ReentrantLock();
public void m1() {
System.out.println("m1开始执行");
try {
lock.lock();
for(int i=0; i<10; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println("i:" + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void m2() {
lock.lock();
System.out.println("m2开始执行");
lock.unlock();
}
public static void main(String[] args) {
MyReentrantLock1 r1 = new MyReentrantLock1();
new Thread(r1::m1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(r1::m2).start();
}
}
1.2、“尝试锁定”ReentrantLock的tryLock方法,这样无法锁定,或者在指定时间内无法锁定,线程可以决定是否继续等待。
也可以指定tryLock的时间,由于tryLock(time)抛出异常,所以要注意unclock的处理,必须放到finally中
public class ReentrantLock3 {
Lock lock = new ReentrantLock();
void m1() {
try {
lock.lock();
for (int i = 0; i < 10; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println(i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/**
* 使用tryLock进行尝试锁定,不管锁定与否,方法都将继续执行
* 可以根据tryLock的返回值来判定是否锁定
* 也可以指定tryLock的时间,由于tryLock(time)抛出异常,所以要注意unclock的处理,必须放到finally中
*/
void m2() {
/*
boolean locked = lock.tryLock();
System.out.println("m2 ..." + locked);
if(locked) lock.unlock();
*/
boolean locked = false;
try {
locked = lock.tryLock(5, TimeUnit.SECONDS);
System.out.println("m2 ..." + locked);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(locked) lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLock3 rl = new ReentrantLock3();
new Thread(rl::m1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(rl::m2).start();
}
}
1.3、ReentrantLock的lockInterruptibly方法,可以对线程interrupt方法做出响应,在一个线程等待锁的过程中,可以被打断。
下面的程序,由于thread1一直执行,thread2始终无法获取锁,就一直等待,所以尝试打断thread2,如果thread2中用lock.lock()锁定,此时无法打断thread2,如果用lock.lockInterruptibly()既可以打断thread2
public class MyReentrantLock4 {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Thread thread1 = new Thread(()->{
try {
System.out.println("t1 start....");
lock.lock();
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
System.out.println("t1 end....");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
Thread thread2 = new Thread(()->{
boolean locked = false;
try {
// lock.lock();
lock.lockInterruptibly();
locked = lock.tryLock();
System.out.println("t2 start....");
TimeUnit.SECONDS.sleep(5);
System.out.println("t2 end....");
} catch (InterruptedException e) {
System.out.println("interrupted!");
} finally {
if(locked) {
lock.unlock();
}
}
});
thread2.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.interrupt();
}
}
1.4、reentrantlock可以指定为公平锁
2、生产者消费者
写一个固定容量同步容器,拥有put和get方法,以及getCount方法,能够支持2个生产者线程以及10个消费者线程的阻塞调用
2.1、 wait,notify实现
(1)wait 99%的情况跟while一起用,而不是和if一起用。原因:在执行之前会进入while再检查一遍,while会一直判断,if只会判断一次,如果有多个线程等待,会不安全。
(2)用notifyAll而不是notify。原因:如果用notify可能出现一个生产者叫醒另外一个也是生产者,被叫醒的生产者也wait了,程序无法继续执行。
2.2、ReentrantLock Condition实现,精确指定哪个线程被唤醒
网友评论