多线程——线程精确控制

实现一个容器,提供两个方法,add,size
写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
1、使用同步容器
注意:确保t2线程先运行,否者t1线程先运行size超过5时t2线程一直无法结束,导致程序无法退出

public class TestSynchronizedContainer {
	volatile List lists = Collections.synchronizedList(new LinkedList<>());

	public void add(Object o) {
		lists.add(o);
	}
	public int size() {
		return lists.size();
	}
	public static void main(String[] args) throws InterruptedException {
		T02_WithVolatile c = new T02_WithVolatile();
		new Thread(() -> {
			while(true) {
				if(c.size() == 5) {
					break;
				}
			}
			//保证线程2先执行
			System.out.println("t2 结束");
		}, "t2").start();
		Thread.sleep(1l);
		new Thread(() -> {
			for(int i=0; i<10; i++) {
				c.add(new Object());
				System.out.println("add " + i);
			}
		}, "t1").start();
	}
}

2、使用wait和notify做到,wait会释放锁,而notify不会释放锁
需要注意的是,运用这种方法,必须要保证t2先执行,也就是首先让t2监听才可以,在添加元素到5个的时候通知第二个线程执行,但是notif不会释放锁,所以如果t1不调用wait方法,则t1会继续执行,执行完后t2才能得到执行,也就是说t1的确是唤醒了t2,但是没有释放锁让t2执行。

public class WaitAndNotify{
	//添加volatile,使t2能够得到通知
	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) {
		WaitAndNotify c = new WaitAndNotify();
		final Object lock = new Object();
		new Thread(() -> {
			synchronized(lock) {
				System.out.println("t2启动");
				if(c.size() != 5) {
					try {
						lock.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println("t2 结束");
				//通知t1继续执行
				lock.notify();
			}
		}, "t2").start();
		try {
			Thread.sleep(1);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		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();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}
		}, "t1").start();
	}
}

3、使用CountDownLatch,这里使用了两个CountDownLatch,分别控制两个线程,如果只有一个,即线程1添加元素到5个的时候通知线程2结束,这个时候线程1通知完后还会继续执行,可能线程1添加到8个的时候,线程2才真正停止。所以通知完线程2停止后线程1得阻塞住,线程2执行完后,再让线程1执行。

public class TestCountDownLatch {
	// 添加volatile,使t2能够得到通知
	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) {
		TestCountDownLatch c = new TestCountDownLatch();
		CountDownLatch latch = new CountDownLatch(1);
		CountDownLatch latchT1 = new CountDownLatch(1);
		new Thread(() -> {
			System.out.println("t2启动");
			if (c.size() != 5) {
				try {
					latch.await();
					//也可以指定等待时间
					//latch.await(5000, TimeUnit.MILLISECONDS);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println("t2 结束");
			latchT1.countDown();
		}, "t2").start();
		try {
			Thread.sleep(1);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		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) {
					// 打开门闩,让t2得以执行
					latch.countDown();
					try {
						latchT1.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}, "t1").start();
	}
}

4、使用LockSupport,这里和上面使用CountDownLatch类似,线程1通知线程2后,线程1继续执行,导致线程2没有及时停止,所以在通知线程2停止时也要让线程1阻塞住

public class TestLockSupport {
	// 添加volatile,使t2能够得到通知
	volatile List lists = new ArrayList();
	public void add(Object o) {
		lists.add(o);
	}
	public int size() {
		return lists.size();
	}
	static Thread t1 = null, t2 = null;
	public static void main(String[] args) {
		TestLockSupport c = new TestLockSupport();

		t1 = 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) {
					LockSupport.unpark(t2);
					LockSupport.park();
				}
			}
		}, "t1");
		t2 = new Thread(() -> {
			System.out.println("t2启动");
			LockSupport.park();
			System.out.println("t2 结束");
			LockSupport.unpark(t1);
		}, "t2");
		t2.start();
		t1.start();
	}
}

5、使用Semaphore,并使t1线程控制t2线程的启动。

public class TestSemaphore {
    // 添加volatile,使t2能够得到通知
    volatile List lists = new ArrayList();
    public void add(Object o) {
        lists.add(o);
    }
    public int size() {
        return lists.size();
    }
    static Thread t1 = null, t2 = null;
    public static void main(String[] args) {
        TestSemaphore c = new TestSemaphore();
        Semaphore s = new Semaphore(1);
        t1 = new Thread(() -> {
            try {
                s.acquire();
                for (int i = 0; i < 5; i++) {
                    c.add(new Object());
                    System.out.println("add " + i);
                }
                s.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                t2.start();
                t2.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                s.acquire();
                for (int i = 5; i < 10; i++) {
                    System.out.println("add "+i);
                }
                s.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t1");
        t2 = new Thread(() -> {
            try {
                s.acquire();
                System.out.println("t2 结束");
                s.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t2");
        t1.start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值