不使用等待/通知机制实现线程间通信
使用sleep()结合while(true)死循环来实现多个线程间通信
package Third; import java.util.ArrayList; import java.util.List; public class MyList { private List list = new ArrayList(); public void add() { list.add("高洪岩"); } public int size() { return list.size(); } }
package Third; public class ThreadA extends Thread { private MyList list; public ThreadA(MyList list) { super(); this.list = list; } @Override public void run() { try { for (int i = 0; i < 10; i++) { list.add(); System.out.println("添加了" + (i + 1) + "个元素"); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class ThreadB extends Thread { private MyList list; public ThreadB(MyList list) { super(); this.list = list; } @Override public void run() { try { while (true) { if (list.size() == 5) { System.out.println("==5了,线程b要退出了!"); throw new InterruptedException(); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class Test { public static void main(String[] args) { MyList service = new MyList(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); } }
虽然两个线程实现了通信,但有一个弊端是,线程ThreadB.java不停地通过while语轮询机制来检测某一个条件,这样会浪费CPU资源。
如果轮询的时间间隔小,更浪费cpu资源;如果轮询时间间隔大,有可能会娶不到想要的数据。所以就需要有一种机制来减少CPU的资源浪费,而且还可以实现在多个线程间通信,它就是“”wait/notify“”机制。
什么是等待/通信机制
等待/通知机制的实现
package Third; public class Test1 { public static void main(String[] args) { try { String newString = new String(""); newString.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } }
出现异常的原因是没有“”对象监视器“”,也就是没有同步加锁
package Third; public class Test2 { public static void main(String[] args) { try { String lock = new String(); System.out.println("syn上面"); synchronized (lock) { System.out.println("syn第一行"); lock.wait(); System.out.println("wait下的代码!"); } System.out.println("syn下面的代码"); } catch (InterruptedException e) { e.printStackTrace(); } } }
线程不能永远等待下去,那样程序就停止不前,不继续向下运行了。如何使呈现wait状态的线程继续运行?答案是notify()
package Third; public class MyThread1 extends Thread { private Object lock; public MyThread1(Object lock) { super(); this.lock = lock; } @Override public void run() { try { synchronized (lock) { System.out.println("开始 wait time=" + System.currentTimeMillis()); lock.wait(); System.out.println("结束 wait time=" + System.currentTimeMillis()); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package Third; public class MyThread2 extends Thread { private Object lock; public MyThread2(Object lock) { super(); this.lock = lock; } @Override public void run() { synchronized (lock) { System.out.println("开始notify time=" + System.currentTimeMillis()); lock.notify(); System.out.println("结束notify time=" + System.currentTimeMillis()); } } }
package Third; public class MyThread2 extends Thread { private Object lock; public MyThread2(Object lock) { super(); this.lock = lock; } @Override public void run() { synchronized (lock) { System.out.println("开始notify time=" + System.currentTimeMillis()); lock.notify(); System.out.println("结束notify time=" + System.currentTimeMillis()); } } }
下面实现前面的size()=5的实验
package Third; import java.util.ArrayList; import java.util.List; public class MyList { private static List list = new ArrayList(); public static void add() { list.add("anyString"); } public static int size() { return list.size(); } }
package Third; public class ThreadA extends Thread { private Object lock; public ThreadA(Object lock) { super(); this.lock = lock; } @Override public void run() { try { synchronized (lock) { if (MyList.size() != 5) { System.out.println("wait begin " + System.currentTimeMillis()); lock.wait(); System.out.println("wait end " + System.currentTimeMillis()); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class ThreadB extends Thread { private Object lock; public ThreadB(Object lock) { super(); this.lock = lock; } @Override public void run() { try { synchronized (lock) { for (int i = 0; i < 10; i++) { MyList.add(); if (MyList.size() == 5) { lock.notify(); System.out.println("已发出通知!"); } System.out.println("添加了" + (i + 1) + "个元素!"); Thread.sleep(1000); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class Run { public static void main(String[] args) { try { Object lock = new Object(); ThreadA a = new ThreadA(lock); a.start(); Thread.sleep(50); ThreadB b = new ThreadB(lock); b.start(); } catch (InterruptedException e) { e.printStackTrace(); } } }
日志信息wait end在最后输出,这也说明notify()执行后并不立即释放锁
方法wait()锁释放与notify()锁不释放
当方法wait()被执行后,锁被自动释放,但执行完notify()方法,锁却不自动释放
package Third; public class Service { public void testMethod(Object lock) { try { synchronized (lock) { System.out.println("begin wait()"); lock.wait(); System.out.println(" end wait()"); } } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class ThreadA extends Thread { private Object lock; public ThreadA(Object lock) { super(); this.lock = lock; } @Override public void run() { Service service = new Service(); service.testMethod(lock); } }
package Third; public class ThreadB extends Thread { private Object lock; public ThreadB(Object lock) { super(); this.lock = lock; } @Override public void run() { Service service = new Service(); service.testMethod(lock); } }
package Third; public class Test { public static void main(String[] args) { Object lock = new Object(); ThreadA a = new ThreadA(lock); a.start(); ThreadB b = new ThreadB(lock); b.start(); } }
下面验证方法notify()被执行后,不释放锁
package Third; public class Service { public void testMethod(Object lock) { try { synchronized (lock) { System.out.println("begin wait() ThreadName=" + Thread.currentThread().getName()); lock.wait(); System.out.println(" end wait() ThreadName=" + Thread.currentThread().getName()); } } catch (InterruptedException e) { e.printStackTrace(); } } public void synNotifyMethod(Object lock) { try { synchronized (lock) { System.out.println("begin notify() ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis()); lock.notify(); Thread.sleep(5000); System.out.println(" end notify() ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis()); } } catch (InterruptedException e) { e.printStackTrace(); } } }
package Third; public class ThreadA extends Thread { private Object lock; public ThreadA(Object lock) { super(); this.lock = lock; } @Override public void run() { Service service = new Service(); service.testMethod(lock); } }
package Third; public class NotifyThread extends Thread { private Object lock; public NotifyThread(Object lock) { super(); this.lock = lock; } @Override public void run() { Service service = new Service(); service.synNotifyMethod(lock); } }
package Third; public class synNotifyMethodThread extends Thread { private Object lock; public synNotifyMethodThread(Object lock) { super(); this.lock = lock; } @Override public void run() { Service service = new Service(); service.synNotifyMethod(lock); } }
package Third; public class Test { public static void main(String[] args) throws InterruptedException { Object lock = new Object(); ThreadA a = new ThreadA(lock); a.start(); NotifyThread notifyThread = new NotifyThread(lock); notifyThread.start(); synNotifyMethodThread c = new synNotifyMethodThread(lock); c.start(); } }