线程通信
2016-06-05 14:42
106 查看
讲解等待唤醒机制之前,有必要搞清一个概念――线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即―― 等待唤醒机制。
等待唤醒机制所涉及到的方法:
wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
等待唤醒机制所涉及到的方法:
wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
public class NumberHolder { private int number; public synchronized void increase() { if (0 != number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能执行到这里说明已经被唤醒 // 并且number为0 number++; System.out.println(number); // 通知在等待的线程 notify(); } public synchronized void decrease() { if (0 == number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能执行到这里说明已经被唤醒 // 并且number不为0 number--; System.out.println(number); notify(); } }public class IncreaseThread extends Thread { private NumberHolder numberHolder; public IncreaseThread(NumberHolder numberHolder) { this.numberHolder = numberHolder; } @Override public void run() { for (int i = 0; i < 20; ++i) { // 进行一定的延时 try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } // 进行增加操作 numberHolder.increase(); } } }public class DecreaseThread extends Thread { private NumberHolder numberHolder; public DecreaseThread(NumberHolder numberHolder) { this.numberHolder = numberHolder; } @Override public void run() { for (int i = 0; i < 20; ++i) { // 进行一定的延时 try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } // 进行减少操作 numberHolder.decrease(); } } }public class NumberTest { public static void main(String[] args) { NumberHolder numberHolder = new NumberHolder(); Thread t1 = new IncreaseThread(numberHolder); Thread t2 = new DecreaseThread(numberHolder); t1.start(); t2.start(); } }因为就是两个线程所以就是可以互相切换,即必须是互相切换,但是如果是四个线程呢?会怎么样呢?那么再来两个线程; 即把其中的NumberTest类改为如下:
public class NumberTest { public static void main(String[] args) { NumberHolder numberHolder = new NumberHolder(); Thread t1 = new IncreaseThread(numberHolder); Thread t2 = new DecreaseThread(numberHolder); Thread t3 = new IncreaseThread(numberHolder); Thread t4 = new DecreaseThread(numberHolder); t1.start(); t2.start(); t3.start(); t4.start(); } }为什么两个线程的时候执行结果正确而四个线程的时候就不对了呢? 因为线程在wait()的时候,接收到其他线程的通知,即往下执行,不再进行判断。两个线程的情况下,唤醒的肯定是另一个线程;但是在多个线程的情况下,执行结果就会混乱无序。比如,一个可能的情况是,一个增加线程执行的时候,其他三个线程都在wait,这时候第一个线程调用了notify()方法,其他线程都将被唤醒,然后执行各自的增加或减少方法。 解决的方法就是:在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。把两个方法中的if改为while即可。
public class NumberHolder { private int number; public synchronized void increase() { while (0 != number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能执行到这里说明已经被唤醒 // 并且number为0 number++; System.out.println(number); // 通知在等待的线程 notify(); } public synchronized void decrease() { while (0 == number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能执行到这里说明已经被唤醒 // 并且number不为0 number--; System.out.println(number); notify(); } }这样就可以解决了线程的混乱的问题。
相关文章推荐
- cocos2dx 历史版本下载问题
- java数学函数
- 剑指Offer----面试题23:从上往下打印二叉树(层序遍历)
- linux下ftp和ftps以及ftp基于mysql虚拟用户认证服务器的搭建
- 检测PC端和移动端的方法总结(转)
- JAVA_OA(五)(番外篇):SpringMVC乱码解决(post,get)
- 北京数联,呵呵
- ubuntu - sublime text3 中文输入(ibus)
- 操作系统---常见进程调度算法
- create table用圆括号()
- 学生常见问题(二)
- (某云平台+VPLC神器)助我解postfix邮件系统的疑问处理
- java变量&常量
- 项目签名
- 函数对象(3)
- python面向对象进阶 反射 单例模式
- HttpServletResponse对象(二)
- PHP面试总结
- 微软自动图像说明技术的最新进展
- ListView、CursorAdatper