线程方法wait()和notify()的使用
实现需求:
开启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()的使用的更多相关文章
- Java多线程:线程状态以及wait(), notify(), notifyAll()
一. 线程状态类型1. 新建状态(New):新创建了一个线程对象.2. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中,变得可运 ...
- 多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify())
多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify()) 1.线程安全,无非就是加锁,访问共享资源时,synchronized 2.线程通信,就是控制各个线程之 ...
- 结束线程方法2 Java提供的中断机制
package com.mozq.thread.interrupt; /** * 注意:调用interrupt()方法,并不会结束线程. * 结束线程的语义:需要我们自己使用3个中断方法构建. * * ...
- 守护线程,需要通过调用线程方法:setDaemon(boolean on)来进行设置
package seday08.thread;/*** @author xingsir * 守护线程又称为后台线程,默认创建出来的线程都是普通线程, 守护线程需要通过调用线程方法:setDaemon( ...
- 创建线程方法&守护线程
创建线程方法1. class mythread extends Thread{ 重写run方法 } mythread m=new mythread () 启动:m.start() 创建线程方法2. c ...
- Java自学-多线程 常见线程方法
Java 常见的线程方法 示例 1 : 当前线程暂停 Thread.sleep(1000); 表示当前线程暂停1000毫秒 ,其他线程不受影响 Thread.sleep(1000); 会抛出Inter ...
- 零基础学习java------day18------properties集合,多线程(线程和进程,多线程的实现,线程中的方法,线程的声明周期,线程安全问题,wait/notify.notifyAll,死锁,线程池),
1.Properties集合 1.1 概述: Properties类表示了一个持久的属性集.Properties可保存在流中或从流中加载.属性列表中每个键及其对应值都是一个字符串 一个属性列表可包含另 ...
- java并发编程(十一)线程间的通信notify通知的遗漏
notify通知的遗漏很容易理解,即threadA还没开始wait的时候,threadB已经notify了,这样,threadB通知是没有任何响应的,当threadB退出synchronized代码块 ...
- Java核心知识点学习----多线程并发之线程间的通信,notify,wait
1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...
随机推荐
- MySQL错误日志(Error Log)
错误日志是一个文本文件,记录了 MySQL Server 每次启动和关闭的详细信息以及运行过程中所有较为严重的警告和错误信息.在遇到问题时,应该首先查看这个文件. 如何开启 使用命令 SHOW VAR ...
- 第8.10节 使用__class__查看Python中实例对应的类
一. 语法释义 __class__属性很简单,直接返回实例对应的类.语法如下: 实例. class 当不知道一个实例的类名又想对类的部分内容进行访问时可以使用__class__返回类. 注意:是返回实 ...
- PyQt(Python+Qt)学习随笔:QListWidget获取指定行对应项的item()方法
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 在列表部件中,可以通过item方法获取指定行对应的项,语法如下: QListWidgetItem i ...
- ❤空植发队 影评网站FilmReviewWeb-团队介绍
空植发队 团队展示&选题 团队展示 团队信息 队名: 空植发队 队员: 罗泉水(队长)3118005101 麦狄龙 3118005103 马志鹏 3118005102 陈鸿畅 3118 ...
- element ui中表格table翻页记忆勾选状态
<el-table ref="multipleTable" :data="datalist" style="width:100%" @ ...
- Win10 .net framework 3.5 安装失败 0x80073712 [解决了]
Win10 .net framework 3.5 安装失败 0x80073712 用了各种办法,一直解决不了. 最后用了: 使用 https://www.microsoft.com/zh-cn/sof ...
- 【题解】P1852 跳跳棋
link 题意 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.棋盘上有3颗棋子,分别在 \(a,b,c\) 这三个位置.我们要通过最少的跳动把他们的位置移动成 \(x,y, ...
- C++笔试题续
第一部分:C++与C语言的差异(1-18)1.C 和 C++ 中 struct 有什么区别? Protection行为 能否定义函数C 无 否,但可以有函数指针C++ 有 可以,默认是public2. ...
- JWT-配置与使用
1.jwt的安装配置 . 1.1安装JWT pip install djangorestframework-jwt==1.11.0 1.2 settings.py配置jwt载荷中的有效期设置 # jw ...
- 关于C++的异常抛出
在接触 throw 之前,我们只知道可以通过函数的返回值来获取和定位错误,比如通过 return 来层层返回是一种方法,但如果牵扯到多层函数调用,那么通过 return 来返回错误显得过于拖沓,这时就 ...