线程方法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 ...
随机推荐
- JVM(五)-垃圾收集器入门
概述: 大家都知道java相较于c.c++而言最大的优点就是JVM会帮助程序员去回收垃圾,实现对内存的自动化管理.那为什么程序员还需要去了解垃圾回收和内存分配?答案很简单,当需要排查各种内存溢内存泄漏 ...
- charles 常用功能 (六)抓包结果列表指展示关注的接口(focus on 功能)
添加关注的接口 2.启用关注接口,添加过滤的地址 3.重新抓包结果 不在上一步配置中的接口,都会隐藏在other host中
- PyQt(Python+Qt)学习随笔:QMainWindow的takeCentralWidget对QDockWidget作用案例图解
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 QMainWindow的takeCentralWidget方法作用是将 ...
- java课堂作业--异常处理
一. 运行结果: 二. 结果: ArrayIndexOutOfBoundsException/内层try-catch 发生ArithmeticException 三. 结果: ArrayIndexOu ...
- Java基础学习之面向对象(4)
目录 1.面向对象概述 1.1.类与对象的关系 1.2.类的具体描述 2.面向对象的三大特性 2.1.继承 2.2.多态 2.3.封装 1.面向对象概述 1.1.类与对象的关系 有对象吗,没有的话我给 ...
- 【学习笔记】最小直径生成树(MDST)
简介 无向图中某一点(可以在顶点上或边上),这个点到所有点的最短距离的最大值最小,那么这个点就是 图的绝对中心. 无向图所有生成树中,直径最小的一个,被称为 最小直径生成树. 图的绝对中心的求法 下文 ...
- 聊聊Spring的FactoryBean其实没那么难
前言 谈到Spring的FactoryBean,就会知道Spring中经典的面试题:FactoryBean和BeanFactory的区别.我们这里就简单概括下: . BeanFactory是接口,提供 ...
- JavaSE22-Lambda表达式&方法引用
1.Lambda表达式 1.1 Lambda表达式的标准格式 1 (形式参数) -> {代码块} 形式参数:如果有多个参数,参数之间用逗号隔开:如果没有参数,留空即可 ->:由英文中画线和 ...
- 【PY从0到1】第一节 安装与界面介绍
本系列是介绍如何用Python进行股票量化交易的课程. 课程内容以记录Python零基础学员从最简单的Python下载及安装开始,到最后能熟练运用Python进行量化交易的专业人员的成长历程.旨在打造 ...
- Java源码赏析(六)Class<T> 类
目的 Class 类是每一个程序员都必须了解的,也是使用反射机制的基础. 这篇文章将Class 类的公共方法大致介绍了一遍(省略了安全.枚举.断言.注解相关代码). 代码 package java.l ...