实现需求:

开启2个线程,1个线程对某个int类型成员变量加1,另外1个减1,但是要次序执行,即如果int型的成员变量是0,则输出01010101这样的结果

代码如下

 1 package test;
2
3 public class Sample {
4
5 private int i;
6
7 public synchronized void increase() {
8
9 if(i != 0) { // 值不为0时,已经加过,释放锁,等待其他线程减为0
10 try {
11 wait();
12 } catch (Exception e) {
13 e.printStackTrace();
14 }
15 }
16
17 // 值为0,需要增加
18 i++;
19 System.out.println(i);
20 // 通知其他线程,可以进行减1的操作了
21 notify();
22 }
23
24 public synchronized void decrease() {
25 if(i == 0) { // 值为0时,已经减过,释放锁,等待其他线程加为1
26 try {
27 wait();
28 } catch (Exception e) {
29 e.printStackTrace();
30 }
31 }
32
33 // 值为1,需要减少
34 i--;
35 System.out.println(i);
36 // 通知其他线程,可以进行加1的操作了
37 notify();
38 }
39
40 public static void main(String[] args) {
41
42 Sample sample = new Sample();
43
44 Thread t1 = new IncreaseThread(sample);
45 Thread t2 = new DecreaseThread(sample);
46
47 t1.start();
48 t2.start();
49 }
50 }
51
52 class DecreaseThread extends Thread {
53
54 private Sample sample;
55
56 public DecreaseThread(Sample sample) {
57 this.sample = sample;
58 }
59
60 @Override
61 public void run() {
62 for (int i = 0; i < 20; i++) {
63 try {
64 Thread.sleep((long) Math.random() * 1000);
65 } catch (Exception e) {
66 e.printStackTrace();
67 }
68
69 sample.decrease();
70 }
71 }
72 }
73
74 class IncreaseThread extends Thread {
75
76 private Sample sample;
77
78 public IncreaseThread(Sample sample) {
79 this.sample = sample;
80 }
81
82 @Override
83 public void run() {
84 for (int i = 0; i < 20; i++) {
85 try {
86 Thread.sleep((long) Math.random() * 1000);
87 } catch (Exception e) {
88 e.printStackTrace();
89 }
90
91 sample.increase();
92 }
93 }
94 }

需求稍作改变,变成:

开启4个线程,2个线程对某个int类型成员变量加1,另外2个减1,但是要次序执行,即如果int型的成员变量是0,则输出01010101这样的结果

如果是直接再生成t3 t4分别是IncreaseThread和DecreaseThread的实例(即t1/t3为IncreaseThread类的实例,t2/t4为DecreaseThread的实例),假设执行流程如下:

(1)t2执行,由于i=0,所以线程等待,释放锁,随机通知一条线程进行执行(notify()方法是通知随机一条线程的)

(2)假设通知到了t4,由于i=0,所以t4线程又等待,锁释放,又随机通知到一条线程进行执行

(3)假设又通知到了t2线程,这个时候,线程的执行是从wait()方法后面开始执行的,不会再去判断i是否等于0了,继续执行,会进行i的自减操作,出现i=-1的局面

所以代码需要修改

 1 package test;
2
3 public class Sample {
4
5 private int i;
6
7 public synchronized void increase() {
8
9 while(i != 0) { // 值不为0时,已经加过,释放锁,等待其他线程减为0
10 try {
11 wait();
12 } catch (Exception e) {
13 e.printStackTrace();
14 }
15 }
16
17 // 值为0,需要增加
18 i++;
19 System.out.println(i);
20 // 通知其他线程,可以进行减1的操作了
21 notify();
22 }
23
24 public synchronized void decrease() {
25 while(i == 0) { // 值为0时,已经减过,释放锁,等待其他线程加为1
26 try {
27 wait();
28 } catch (Exception e) {
29 e.printStackTrace();
30 }
31 }
32
33 // 值为1,需要减少
34 i--;
35 System.out.println(i);
36 // 通知其他线程,可以进行加1的操作了
37 notify();
38 }
39
40 public static void main(String[] args) {
41
42 Sample sample = new Sample();
43
44 Thread t1 = new IncreaseThread(sample);
45 Thread t2 = new DecreaseThread(sample);
46 Thread t3 = new IncreaseThread(sample);
47 Thread t4 = new DecreaseThread(sample);
48
49 t1.start();
50 t2.start();
51 t3.start();
52 t4.start();
53 }
54 }
55
56 class DecreaseThread extends Thread {
57
58 private Sample sample;
59
60 public DecreaseThread(Sample sample) {
61 this.sample = sample;
62 }
63
64 @Override
65 public void run() {
66 for (int i = 0; i < 20; i++) {
67 try {
68 Thread.sleep((long) Math.random() * 1000);
69 } catch (Exception e) {
70 e.printStackTrace();
71 }
72
73 sample.decrease();
74 }
75 }
76 }
77
78 class IncreaseThread extends Thread {
79
80 private Sample sample;
81
82 public IncreaseThread(Sample sample) {
83 this.sample = sample;
84 }
85
86 @Override
87 public void run() {
88 for (int i = 0; i < 20; i++) {
89 try {
90 Thread.sleep((long) Math.random() * 1000);
91 } catch (Exception e) {
92 e.printStackTrace();
93 }
94
95 sample.increase();
96 }
97 }
98 }

这里把if判断改成了while循环,因为wait方法之后,应该是需要重复判断一次i的情况的,这样就不会出现数字不对的情况了

这里有一条基本原则:

永远在while循环里而不是if语句下使用wait。这样,会在线程暂停恢复后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知

线程方法wait()和notify()的使用的更多相关文章

  1. Java多线程:线程状态以及wait(), notify(), notifyAll()

    一. 线程状态类型1. 新建状态(New):新创建了一个线程对象.2. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中,变得可运 ...

  2. 多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify())

    多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify()) 1.线程安全,无非就是加锁,访问共享资源时,synchronized 2.线程通信,就是控制各个线程之 ...

  3. 结束线程方法2 Java提供的中断机制

    package com.mozq.thread.interrupt; /** * 注意:调用interrupt()方法,并不会结束线程. * 结束线程的语义:需要我们自己使用3个中断方法构建. * * ...

  4. 守护线程,需要通过调用线程方法:setDaemon(boolean on)来进行设置

    package seday08.thread;/*** @author xingsir * 守护线程又称为后台线程,默认创建出来的线程都是普通线程, 守护线程需要通过调用线程方法:setDaemon( ...

  5. 创建线程方法&守护线程

    创建线程方法1. class mythread extends Thread{ 重写run方法 } mythread m=new mythread () 启动:m.start() 创建线程方法2. c ...

  6. Java自学-多线程 常见线程方法

    Java 常见的线程方法 示例 1 : 当前线程暂停 Thread.sleep(1000); 表示当前线程暂停1000毫秒 ,其他线程不受影响 Thread.sleep(1000); 会抛出Inter ...

  7. 零基础学习java------day18------properties集合,多线程(线程和进程,多线程的实现,线程中的方法,线程的声明周期,线程安全问题,wait/notify.notifyAll,死锁,线程池),

    1.Properties集合 1.1 概述: Properties类表示了一个持久的属性集.Properties可保存在流中或从流中加载.属性列表中每个键及其对应值都是一个字符串 一个属性列表可包含另 ...

  8. java并发编程(十一)线程间的通信notify通知的遗漏

    notify通知的遗漏很容易理解,即threadA还没开始wait的时候,threadB已经notify了,这样,threadB通知是没有任何响应的,当threadB退出synchronized代码块 ...

  9. Java核心知识点学习----多线程并发之线程间的通信,notify,wait

    1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...

随机推荐

  1. Mysql-索引分析查询性能

    explain 全文只有一个关键点,那就是explain,explain 显示了MySQL如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句.简单讲,它的作用就 ...

  2. 第8.26节 重写Python类中的__getattribute__方法实现实例属性访问捕获

    一. 引言 在<第7.23节 Python使用property函数定义属性简化属性访问的代码实现>和<第7.26节 Python中的@property装饰器定义属性访问方法gette ...

  3. 上传到github

    我是为了自己下次不用再找github上传的地方了,索性就复制了一篇 转载于 https://blog.csdn.net/m0_37725003/article/details/80904824 首先你 ...

  4. Jenkins环境搭建(8)-邮件未能正常发送

    昨天,在使用jenkins构建项目时,出现了个问题,问题是:jenkins控制台日志显示邮件发送成功,但实际没有成功. 此前,jenkins的配置,项目构建后,是能正常发送邮件的,可这次突然就不行了, ...

  5. AWT01-体系概述

    1.概述 AWT(Abstract Window Toolkit),中文译为抽象窗口工具包,该包提供了一套与本地图形界面进行交互的接口,是Java提供的用来建立和设置Java的图形用户界面的基本工具. ...

  6. f12 Network的解析

    Chrome开发者工具面板 面板上包含了Elements面板.Console面板.Sources面板.Network面板.Timeline面板.Profiles面板.Application面板.Sec ...

  7. js下 Day20、综合案例

    一.购物车 效果图: 功能思路分析: 1. 面向对象框架 2. 模拟数据 1.多个店铺数组套对象 2.每个店铺多个商品,数组套对象

  8. 移动端 CSS3动画属性

    一.transform 转换属性 #1. translate位移 transform : translate(50px,100px); //把元素水平移动 50 像素,垂直移动 100 像素 tran ...

  9. Jmeter二次开发——基于Java请求

    简述 这近几年,越来越多非http的协议需要进行性能测试,包括不仅限于各类rpc.mq.缓存等.对于这些协议,市面上可能没有现成的工具可以直接使用,这个时候,我们可以自己动手,通过编写相应的JavaS ...

  10. 【漏洞复现】Struts2-045分析(CVE-2017-5638)

    如果需要大佬写好的脚本,可以直接去github上面搜 struts2 - 045 一个还比较出名的漏洞,因为涉及到利用Gopher协议反弹shell,所以写篇文章来简单学习下这个漏洞. Struts2 ...