问题描述
设计一个容器,有add和size两个方法,然后有两个线程,一个线程往容器里加10个数,另一个
线程用来控制第一个线程,当加到5个数时,线程停止,让第一个线程继续加数
方法一(Synchronized)
1.解题思路
直接在类里定义一个list,提供add()和size()两个方法。主方法new两个线程t1和t2,当容器数字个数不为5时,t2线程阻塞。这段时间,t1线程不断执行add()方法,当达到5个数后,t1唤醒t2,自己进入阻塞状态。t2被唤醒后,打印“t2停止”,然后又唤醒t1线程,添加剩下的数字
2.代码实现
public class Synchronized {
volatile List lists = new ArrayList();
public void add(Object obj) {
lists.add(obj);
}
public int size() {
return lists.size();
}
public static void main(String[] args) {
Synchronized ex=new Synchronized();
final Object lock=new Object();
new Thread(()->{
synchronized(lock){
System.out.println("t2启动");
if(ex.size()!=5){
try{
lock.wait();
}
catch(Exception e){
e.printStackTrace();
}
}
System.out.println("t2停止");
lock.notify();
}
},"t2").start();
new Thread(()->{
synchronized(lock){
System.out.println("t1启动");
for(int i=0;i<10;i++){
ex.add(new Object());
System.out.println("add "+i);
if(ex.size()==5){
lock.notify();
try{
lock.wait();
}
catch(Exception e){
e.printStackTrace();
}
}
}
}
},"t1").start();
}
}
方法二(ReentrantLock+Condition)
1.解题思路
也是利用阻塞的机制,唤醒和等待的时机与方法一相同,只是写法不同。
2.代码实现
public class ReentrantLock_Method {
volatile List lists = new ArrayList();
public void add(Object obj) {
lists.add(obj);
}
public int size() {
return lists.size();
}
private static Lock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
public static void main(String[] args) {
ReentrantLock_Method ex=new ReentrantLock_Method();
new Thread(()->{
lock.lock();
System.out.println("t2启动");
if(ex.size()!=5){
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2停止");
condition.signal();
lock.unlock();
},"t2").start();
new Thread(()->{
lock.lock();
System.out.println("t1启动");
for(int i=0;i<10;i++){
ex.add(new Object());
System.out.println("add "+i);
if(ex.size()==5){
condition.signal();
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
lock.unlock();
},"t1").start();
}
}
方法三(Park)
1.解题思路
当容器数字个数不为5时,停住t2,此时t1一直往容器加数字,当加满5个数后,放行t2,停住t1。之后打印“结束t2”,放行t1,此时t2线程已结束,t1添加完剩下的数字,同样结束自己。
2.代码实现
public class Park {
volatile List lists = new ArrayList();
public void add(Object obj) {
lists.add(obj);
}
public int size() {
return lists.size();
}
static Thread t1=null,t2=null;
public static void main(String[] args) {
Park ex=new Park();
t2=new Thread(()->{
System.out.println("t2启动");
if(ex.size()!=5){
LockSupport.park(t2);
}
System.out.println("t2停止");
LockSupport.unpark(t1);
},"t2");
t1=new Thread(()->{
System.out.println("t1启动");
for(int i=0;i<10;i++){
ex.add(new Object());
System.out.println("add "+i);
if(ex.size()==5){
LockSupport.unpark(t2);
LockSupport.park(t1);
}
}
},"t1");
t2.start();
t1.start();
}
}
方法四(CountDownLatch)
1.解题思路
CountDownLatch又称“门闩”,当容器中数字个数不为5时,闩住t2,此时t1一直往里加数字,当加满5个数之后,执行countDown()方法,并闩住t1,此时t2被解开,打印“停止t2”后,解开t1,t1线程继续添加完剩下的数字。
2.代码实现
public class Latch {
volatile List lists = new ArrayList();
public void add(Object obj) {
lists.add(obj);
}
public int size() {
return lists.size();
}
public static void main(String[] args) {
Latch ex=new Latch();
CountDownLatch latch1=new CountDownLatch(1);
CountDownLatch latch2=new CountDownLatch(1);
new Thread(()->{
System.out.println("t2启动");
while(ex.size()!=5){
try{
latch2.await();
}
catch(Exception e){
e.printStackTrace();
}
}
System.out.println("t2停止");
latch1.countDown();
},"t2").start();
new Thread(()->{
System.out.println("t1启动");
for(int i=0;i<10;i++){
ex.add(new Object());
System.out.println("add "+i);
if(ex.size()==5){
latch2.countDown();
try{
latch1.await();
}
catch(Exception e){
e.printStackTrace();
}
}
}
},"t1").start();
}
}
测试
所有的方法执行完之后,测试结果均如下图所示: