有一道面试题, 有一个集合,一个线程t1往里面加元素,当集合的size为5的时候,让t2线程结束;
三种实现方法:
方法一: 使用volatile
package thread;
import java.util.ArrayList;
import java.util.List;
/**
* Created by ZWZS on 2018/4/3.
* 有一个list,一个线程往里面添加元素,当list.size()长度为5的时候,通知线程2,让线程2结束
* 第一种方式,使用volatile来实现,使用volatile时,线程t2,一直处于while(true),比较消耗性能
* 可以采用 wait()和notify()优化
*/
public class NotifyStop {
private volatile static List<String> list = new ArrayList<>();
public void add(String s) {
list.add(s);
System.out.println(Thread.currentThread().getName() + " " + s);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void get() {
while (true) {
if (list.size() == 5) {
System.out.println("t2结束");
return;
}
}
}
public static void main(String[] args) {
NotifyStop notifyStop = new NotifyStop();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
notifyStop.add("abc");
}
}, "t1").start();
new Thread(() -> {
notifyStop.get();
}, "t2").start();
}
}
使用voltaile时,线程t2处于while(true)循环中,比较消耗性能,可以让集合的size()等于5的时候再执行.引申出第二种方法;
第二种方法: 使用wait()和notify();
package thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Created by ZWZS on 2018/4/3.
* 有一个list,一个线程往里面添加元素,当list.size()长度为5的时候,通知线程2,让线程2结束
* 第二种方式,使用wait()和notify()来优化
* 可以采用 wait()和notify()优化
*/
public class NotifyStop2 {
private static List<String> list = new ArrayList<>();
private final Object lock = new Object();
public void add(String s) {
synchronized (lock) {
list.add(s);
System.out.println(Thread.currentThread().getName() + " " + s);
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (list.size() == 5) {
lock.notify();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void get() {
synchronized (lock) {
if (list.size() != 5) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2结束");
lock.notify();
}
}
public static void main(String[] args) {
NotifyStop2 notifyStop2 = new NotifyStop2(); //特别注意使用同一个对象进行调用
new Thread(() -> {
for (int i = 0; i < 10; i++) {
notifyStop2.add("abc");
}
}, "t1").start();
new Thread(() -> {
notifyStop2.get();
}, "t2").start();
}
}
第三种方法: 使用CountdownLatch,线程2首先await(),当countdownLatch执行一次countdown时,线程2就执行一次.
package thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Created by ZWZS on 2018/4/3.
* 有一个list,一个线程往里面添加元素,当list.size()长度为5的时候,通知线程2,让线程2结束
* 第三种方式,使用countdownLatch来搞定
*/
public class NotifyStop3 {
private static List<String> list = new ArrayList<>();
private final CountDownLatch countDownLatch = new CountDownLatch(1);
public void add(String s) {
list.add(s);
System.out.println(Thread.currentThread().getName() + " " + s);
if (list.size() == 5) {
countDownLatch.countDown();
}
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void get() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (list.size() == 5) {
System.out.println("t2收到通知");
}
}
public static void main(String[] args) {
NotifyStop3 notifyStop3 = new NotifyStop3(); //特别注意使用同一个对象进行调用
new Thread(() -> {
for (int i = 0; i < 10; i++) {
notifyStop3.add("abc");
}
}, "t1").start();
new Thread(() -> {
notifyStop3.get();
}, "t2").start();
}
}
使用wait()和notify()时,要注意wait()会释放锁,而notify()不会释放锁,推荐使用countdownLatch.