一道面试题:实现一个容器,提供两个方法,add,size,写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束线程2
第一种,使用wait()和notify()来实现
public class test {
volatile List lists = new ArrayList();
public void add(Object o){
lists.add(o);
}
public int size(){
return lists.size();
}
public static void main(String[] args) {
test c = new test();
Object lock = new Object();
new Thread(()->{
synchronized (lock) {
System.out.println("t2启动");
if (c.size() != 5) {
try {
lock.wait();//释放锁
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("t2结束");
lock.notify();
}
}," t2").start();
new Thread(()->{
System.out.println("t1启动");
synchronized (lock) {
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add " + i);
if (c.size() == 5) {
lock.notify();//唤醒当前等待线程,但是不会释放当前线程持有的锁,所以T2线程无法获得锁,依然无法执行
try {
lock.wait();//释放锁,T2才能得到锁得以执行
} catch (Exception e) {
e.printStackTrace();
}
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "t1").start();
}
}
第二种方法,可以使用CountDownLatch来进行控制
public class test {
volatile List lists = new ArrayList();
public void add(Object o){
lists.add(o);
}
public int size(){
return lists.size();
}
public static void main(String[] args) {
test c = new test();
CountDownLatch latch = new CountDownLatch(5);
new Thread(()->{
System.out.println("t2启动");
if (c.size() != 5) {
try {
latch.await();//准备
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("t2结束");
}
}," t2").start();
new Thread(()->{
System.out.println("t1启动");
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add " + i);
if (c.size() == 5) {
latch.countDown();//减一操作
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}, "t1").start();
}
}
CountDownLatch 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了