思路:开启两个线程,线程t1添加元素,线程t2监控元素个数为5。如何保证元素个数为5的时候t2执行,这里就思考如何再元素个数为5的时候t2拿到锁执行,t1等待。直到t2执行完之后t1再拿到锁。
第一种方法:
public class waitFiveSecondTest {
volatile List list = new ArrayList<>();
public void add(Object o){
list.add(o);
}
public int size(){
return list.size();
}
public static void main(String[] args) {
waitFiveSecondTest w = new waitFiveSecondTest();
final Object lock = new Object();
new Thread(()->{
System.out.println("t2启动鸟");
synchronized (lock){
if(w.size()!=5){
try {
lock.wait(); //1、t2先执行,元素个数还没有到5的时候wait()等待,释放锁给t1。
//2、直到t1wait()释放了锁之后,t2重新拿到锁执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2执行结束鸟");
lock.notify(); //3、t2执行完了之后,需要唤醒t1,直到t2执行完之后锁释放。t1拿到继续添加元素
}
},"t2").start();
new Thread(()->{
synchronized (lock){
System.out.println("t1启动鸟"); //t1拿到锁了开始启动执行添加元素
for (int i = 0; i <10 ; i++) {
w.add(new Object());
System.out.println("add"+i);
if(w.size()==5){ //t1往容器里面添加元素到5的时候
lock.notify(); //notify唤醒t2.但是notify不会释放锁,所以t2还不能执行
try {
lock.wait(); //那么需要让t1释放锁,让t2拿到。直到t2执行完,并唤醒t1,t1继续执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("t1执行结束鸟");
}
},"t1").start();
}
}
方法一程序略微复杂。其实就是使用了wait和notyfy方法来控制锁。这里首先要理解wait()是释放了锁的,但是notyfy()没有释放锁。所以需要注意。
接着看下方法二:对于方法1的优化,方法1之所以复杂就是因为控制锁的时候需要两个线程协调锁。所以要程序更简单使用一个控制锁的flag就好,这里使用门栓CountDownLatch。CountDownLatch中值1-->0的时候们拴就开了,countDown()方法开拴。仍然是上面的思路,t2等待,t1添加元素到5给t2执行。
public class waitFiveSecondTest {
volatile List list = new ArrayList<>();
public void add(Object o){
list.add(o);
}
public int size(){
return list.size();
}
public static void main(String[] args) {
waitFiveSecondTest w = new waitFiveSecondTest();
CountDownLatch latch= new CountDownLatch(1);
new Thread(()->{
System.out.println("t2启动鸟");
if(w.size()!=5){
try {
latch.await(); //等着开门,await不需要锁定任何对象。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2执行结束鸟");
},"t2").start();
new Thread(()->{
System.out.println("t1启动鸟");
for (int i = 0; i <10 ; i++) {
w.add(new Object());
System.out.println("add"+i);
if(w.size()==5){
latch.countDown();
}
}
System.out.println("t1执行结束鸟");
},"t1").start();
}
}