Java线程:线程的交互

2023-10-30

本文转载至:http://lavasoft.blog.51cto.com/62575/99157

线程交互是比较复杂的问题,SCJP要求不很基础:给定一个场景,编写代码来恰当使用等待、通知和通知所有线程。
 
一、线程交互的基础知识
 
SCJP所要求的线程交互知识点需要从 java.lang.Object的类的三个方法来学习:
 
 void notify() 
          唤醒在此对象监视器上等待的单个线程。 
 void notifyAll() 
          唤醒在此对象监视器上等待的所有线程。 
 void wait() 
          导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
 
当然,wait()还有另外两个重载方法:
 void wait(long timeout) 
          导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。 
 void wait(long timeout, int nanos) 
          导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
 
以上这些方法是帮助线程传递线程关心的时间状态。
 
关于等待/通知,要记住的关键点是:
必须从同步环境内调用wait()、notify()、notifyAll()方法。线程不能调用对象上等待或通知的方法,除非它拥有那个对象的锁。
wait()、notify()、notifyAll()都是Object的实例方法。与每个对象具有锁一样,每个对象可以有一个线程列表,他们等待来自该信号(通知)。线程通过执行对象上的wait()方法获得这个等待列表。从那时候起,它不再执行任何其他指令,直到调用对象的notify()方法为止。如果多个线程在同一个对象上等待,则将只选择一个线程(不保证以何种顺序)继续执行。如果没有线程等待,则不采取任何特殊操作。
 
下面看个例子就明白了:
package com.mbl.main;

import com.mbl.MyThread;

public class ThreadDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyThread thread = new MyThread(); 
        //启动计算线程 
		thread.start(); 
		//线程A拥有b对象上的锁。线程为了调用wait()或notify()方法,该线程必须是那个对象锁的拥有者 
		synchronized(thread){ 
            try { 
                System.out.println("等待对象b完成计算。。。"); 
                //当前线程A等待 
                thread.wait(); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            System.out.println("b对象计算的总和是:" + thread.total); 
		}
	}

}
package com.mbl;

public class MyThread extends Thread {
	
	public int total;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		 synchronized (this) { 
	            for (int i = 0; i < 101; i++) { 
	                total += i; 
	            } 
	            //(完成计算了)唤醒在此对象监视器上等待的单个线程,在本例中线程A被唤醒 
	            notify(); 
	        } 
	}
	
	

}

运行截图:



千万注意:
当在对象上调用wait()方法时,执行该代码的线程立即放弃它在对象上的锁。然而调用notify()时,并不意味着这时线程会放弃其锁。如果线程荣然在完成同步代码,则线程在移出之前不会放弃锁。因此,只要调用notify()并不意味着这时该锁变得可用。==(对象调用wait方法,立即放弃对象锁,对象调用notify方法,在同步代码没有执行完毕,不会放弃锁)。
二、多个线程在等待一个对象锁时候使用notifyAll()
 
在多数情况下,最好通知等待某个对象的所有线程。如果这样做,可以在对象上使用notifyAll()让所有在此对象上等待的线程冲出等待区,返回到可运行状态。

package com.mbl.main;


import com.mbl.message.Message;
import com.mbl.message.Notifier;
import com.mbl.message.Waiter;

public class RunnableDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		    Message msg = new Message("process it");
	        Waiter waiter = new Waiter(msg);
	        new Thread(waiter,"waiter").start();

	        Waiter waiter1 = new Waiter(msg);
	        new Thread(waiter1, "waiter1").start();

	        Notifier notifier = new Notifier(msg);
	        new Thread(notifier, "notifier").start();
	   
	}

}

package com.mbl.message;

import java.io.Serializable;

public class Message implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private String message;

	public Message(String message) {
		super();
		this.message = message;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

}

package com.mbl.message;

public class Notifier implements Runnable {
	private Message msg;

	public Notifier(Message msg) {
		this.msg = msg;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		String name = Thread.currentThread().getName();
		System.out.println(name + " started");
		try {
			Thread.sleep(1000);
			synchronized (msg) {
				msg.setMessage(name + " Notifier work done");
				//msg.notify();
				 msg.notifyAll();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

package com.mbl.message;

public class Waiter implements Runnable {
	private Message msg;

	public Waiter(Message m) {
		this.msg = m;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		String name = Thread.currentThread().getName();
		synchronized (msg) {
			try {
				System.out.println(name + " waiting to get notified at time:" + System.currentTimeMillis());
				msg.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(name + " waiter thread got notified at time:" + System.currentTimeMillis());
			// process the message now
			System.out.println(name + " processed: " + msg.getMessage());
		}
	}

}
当我们调用以上的代码时可以看到以下的输出,但并没有结束(完成),因为有两个线程等待同一个Message对象,但notify()方法只能唤醒一个线程,另一个线程仍然在等待被唤醒。

notify()

waiter waiting to get notified at time:1492417006932
waiter1 waiting to get notified at time:1492417006933
notifier started
waiter waiter thread got notified at time:1492417007934
waiter processed: notifier Notifier work done


如果我们注释掉Notifier类中的notify() 方法的调用,并打开notifyAll() 方法的调用,将会有以下的输出信息。

notifyAll()

waiter waiting to get notified at time:1492417072173
waiter1 waiting to get notified at time:1492417072173
notifier started
waiter1 waiter thread got notified at time:1492417073175
waiter1 processed: notifier Notifier work done
waiter waiter thread got notified at time:1492417073175
waiter processed: notifier Notifier work done

一旦notifyAll()方法唤醒所有的Waiter线程,程序将会执行完成并退出。




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java线程:线程的交互 的相关文章

  • (Java 基础知识) Java反射

    本篇文章依旧采用小例子来说明 因为我始终觉的 案例驱动是最好的 要不然只看理论的话 看了也不懂 不过建议大家在看完文章之后 在回过头去看看理论 会有更好的理解 下面开始正文 案例1 通过一个对象获得完整的包名和类名 1 2 3 4 5 6
  • Java 终止嵌套for 循环总结

    public class NestedLoopDemo public static void main String args 第一步 构建嵌套for 循环 for int i 0 i lt 10 i for int j 0 j lt 10
  • Java 反射 与 主要API

    控制你的大脑 控制你的行为 你会得到更多 收获很多 文章目录 一 反射相关的主要API 二 代码例子演示 三 反射测试类 一 反射相关的主要API API 名称 代表含义 Java lang class 代表一个类 java lang re
  • java 多线程 总结三

    本文转载至 http blog csdn net vking wang article details 9952063 1 synchronized 把代码块声明为 synchronized 有两个重要后果 通常是指该代码具有 原子性 at
  • Java线程:并发协作-死锁

    本文转载至 http lavasoft blog 51cto com 62575 222074 Java线程 并发协作 死锁 线程发生死锁可能性很小 即使看似可能发生死锁的代码 在运行时发生死锁的可能性也是小之又小 发生死锁的原因一般是两个
  • 线程管理之获取和设置线程信息

    获取和设置线程信息 Thread类的对象中保存了一些属性信息能够帮助我们来辨别每一个线程 知道它的状态 调整控制其优先级 这些属性是 ID 每个线程的独特标识 Name 线程的名称 Priority 线程对象的优先级 优先级别在1 10之间
  • (java 基础知识)java序列化和反序列话总结

    序列化 将java对象转换为字节序列的过程叫做序列化 反序列化 将字节对象转换为java对象的过程叫做反序列化 通常情况下 序列化有两种用途 1 把对象的字节序列永久的保存在硬盘中 2 在网络上传输对象的字节序列 相应的API java i
  • Java线程:新特征-有返回值的线程

    本文转载至 http lavasoft blog 51cto com 62575 222082 在Java5之前 线程是没有返回值的 常常为了 有 返回值 破费周折 而且代码很不好写 或者干脆绕过这道坎 走别的路了 现在Java终于有可返回
  • java 多线程学习笔记之 线程互斥

    许多线程共享同一数据 这种情况在现实的生活中也是经常发生的 比如火车站的火车票售票系统 火车票售票系统是一个常年运行的系统 为了满足乘客的需求 我们不能只设一个窗口 必须设很多的售票窗口 每个售票窗口就像一个线程 它们各自运行 共同访问相同
  • 使用 IO 流 读取 本 地 文 件 (两种方式)

    使用IO 流读取本地文件 public class FileReadWrite public static void main String args FileReader fr null try 1 创建读取文件 fr new FileR
  • Java线程:线程的调度-守护线程

    本文转载至 http lavasoft blog 51cto com 62575 221845 Java线程 线程的调度 守护线程 守护线程与普通线程写法上基本么啥区别 调用线程对象的方法setDaemon true 则可以将其设置为守护线
  • 代码质量保障第2讲:单元测试 - 浅谈单元测试

    代码质量保障第2讲 单元测试 浅谈单元测试 本文是代码质量保障第2讲 浅谈单元测试 单元测试 unit testing 是指对软件中的最小可测试单元进行检查和验证 这是基础 所以围绕着单元测试 我从网上搜集和总结了相关的概念 以助你完善体系
  • (java 基础知识) Java 安全套接字--javax.net.ssl

    有关SSL的原理和介绍在网上已经有不少 对于Java下使用keytool生成证书 配置SSL通信的教程也非常多 但如果我们不能够亲自动手做一个SSL Sever和SSL Client 可能就永远也不能深入地理解Java环境下 SSL的通信是
  • java并发包:生产者消费者模式

    本文转载至 http blog csdn net a910626 article details 51900974 生产者消费者模式是一个经典的多线程设计模式 它为多线程间的协作提供了良好的解决方案 在生产者消费者模式中 通常有两类线程 即
  • Java线程:线程状态的转换

    本文转载至 http lavasoft blog 51cto com 62575 99153 一 线程状态类型 1 新建状态 New 新创建了一个线程对象 2 就绪状态 Runnable 线程对象创建后 其他线程调用了该对象的start 方
  • (Java基础知识) 几种Java任务调度比较

    前言 任务调度是指基于给定时间点 给定时间间隔或者给定执行次数自动执行任务 本文由浅入深介绍四种任务调度的 Java 实现 Timer ScheduledExecutor 开源工具包 Quartz 开源工具包 JCronTab 此外 为结合
  • (Java 基础知识) Java 正则表达式

    一 概述 正则表达式是Java处理字符串 文本的重要工具 Java对正则表达式的处理集中在以下两个两个类 java util regex Matcher 模式类 用来表示一个编译过的正则表达式 java util regex Pattern
  • Java线程:线程的调度-休眠

    本文转载至 http lavasoft blog 51cto com 62575 221790 Java线程 线程的调度 休眠 Java线程调度是Java多线程的核心 只有良好的调度 才能充分发挥系统的性能 提高程序的执行效率 这里要明确的
  • 线程管理之Thread类相关方法简介

    CurrentThread 静态方法 currentThread 方法可返回代码段正在被那个线程调用的信息 简单案列 打印main 方法 正在被那个线程调用 package com zzg thread import com zzg obj
  • java 多线程学习笔记之 线程实现(线程阻塞)

    java 实现线程方法主要分为两种方法 一种是继承 java lang Thread 另一种实现java lang Runnable接口 对于直接继承Thread 的类来说 代码大致框架是 public class MyThread ext

随机推荐

  • Qemu-KVM安装

    目录 前提准备 1 虚拟机需要GNOME界面 如果是字符界面需要下载安装GNOME界面 2 安装vncviewer 3 安装xshell SecureCRT xftp WinSCP 或finalshell 一 Qemu KVM虚拟化环境搭建
  • java可用的动态脚本引擎和动态代码执行

    文章目录 1 javascript语法引擎 1 1 rhino 1 2 nashorn 1 3 j2v8 2 Java语法引擎 2 1 Groovy java的ScriptEngine脚本引擎 支持代码动态执行 代码修改后不需要重启JVM进
  • AAAI 2022 论文列表

    链接及代码之后会更新 GitHub链接 https github com gbstack AAAI 2022 papers Scaled ReLU Matters for Training Vision Transformers Picha
  • 第三章、中台实践-业务中台建设

    第三章 业务中台建设 3 1 什么事业务中台 从业务运行机制和系统开发机制两个维度 展开产生建设业务中台的主要内容 3 1 1 业务中台定义 业务中台是以业务领域划分边界 形成高内聚 低耦合的面向业务领域的能力中心 打造持续演进的企业级业务
  • JAVA实现杨辉三角的三种方式

    一 前言 既然是实现杨辉三角 就要知道什么是杨辉三角 如下图 就是两种杨辉三角 1 等边形状的杨辉三角 2 直角形状的杨辉三角 在知道这两种都是杨辉三角之后 我们就来实现利用java语言打印出杨辉三角 二 杨辉三角的规律 第n行有n个数字
  • 【Consistency Models】复现指导以及效果分析。

    Consistency Models 复现指导以及效果分析 1 先看结果 2 复现指导 3 将结果可视化 总结 1 先看结果 如果没看过论文的建议先看看总结笔记 终结扩散模型 Consistency Models OpenAI开源新模型代码
  • java截取字符串中的一部分字符,我先收藏为敬

    Spring框架自诞生以来一直备受开发者青睐 有人亲切的称之为 Spring 全家桶 Spring更是避免了重复造轮子的工作并跟随着互联网行业的发展做出不断的更新 很多研发人员把spring看作心目中最好的Java项目 没有之一 可以毫不夸
  • 三维气体扩散模拟matlab仿真

    目录 1 算法仿真效果 2 MATLAB源码 3 算法概述 4 部分参考文献 1 算法仿真效果 matlab2022a仿真结果如下 2 MATLAB源码 订阅用户可以获得任意一份完整代码 私信博主 留言文章链接和邮箱地址 一般第二天下午4点
  • 什么是静态变量和静态方法?如何在Java中使用它们?什么是同步和异步?如何在Java中进行同步和异步编程?什么是单元测试?如何在Java中进行单元测试?

    单元测试是一种软件测试方法 它用于测试一个软件系统的最小可测试单元 在Java中 JUnit是最常用的单元测试框架之一 它提供了一些注解和断言 可以方便地编写和运行测试用例 除了JUnit之外 Mockito也是一个非常有用的测试框架 它允
  • (转) 如何将notepad++添加到右键

    工具 原料 win 7系统 Notepad 方法 步骤 左下角点击 开始 gt 运行 gt regedit 打开注册表编辑器 在HKEY CLASSSES ROOT Shell 下 在Shell下 新建项命名为Open With Notep
  • 卧槽,做Python兼职又接了一个大单,真香

    每年的第一季度 是Python兼职接单的高潮期 近段时间 各行业对爬虫类和数分类服务的需求量呈指数级的暴增 圈子里的朋友双休都没闲着 趁着旺季接单大赚一笔 所以 最近在csdn后台咨询技术变现 兼职接单问题的朋友也越来越多 最近十天收到了六
  • 【数据库原理及应用教程(第4版

    文章目录 一 选择题 二 填空题 三 简答题 Reference 一 选择题 1 2 3 4 5 6 7 8 9 10 C B D C D B A B D B 11 12 13 14 15 16 17 18 19 20 C D A D B
  • Spring启动执行流程梳理

    注 本文梳理启动流程使用的Spring版本 4 0 2 RELEASE 使用spring配置 都需要在web xml中配置一个spring的监听器和启动参数 context param 如下
  • 基于视觉的移动平台运动目标检测

    1 声明 本文为自己的研究总结 主要根据各类文献总结而来 内容上可能有些不全面 不客观 这篇博文主要介绍的是基于视觉的移动平台运动目标检测 写这篇博文的目的主要是对自己一个阶段性总结 也希望能够帮助做这方面研究的同学 2 引言 首先 我们来
  • Nacos + Prometheus + Grafana 搭建走起~

    小伙伴们好呀 这两天在本地搭建了这个 Nacos Prometheus Grafana 主要是为了这个 nacos 填坑 然后顺便搭下这个监控中心 哈哈 文章内容比较琐碎 看完你可以了解到 怎么选择 nacos 版本 可能会踩到的坑 没错
  • 一些概念的解释

    转移支付 财政转移支付是以各级政府之间所存在的财政能力差异为基础 以实现各地公共服务水平的均等化为主旨 而实行的一种财政资金转移或财政平衡制度 用人话说 就是大家一起收税 三分留地方 七分归国家 实际上不同税种比例不同 归国家的这些国家在根
  • DELL R740服务器系统安装详细过程

    RAID配置 1 开机F2进入bios 2 选择device setting 3 Integrated Raid controller 1 xxxxxx raid 卡型号 一般是第一行 4 选择 Main Menu
  • java中上传本地图片

    如果你想上传多张图片 http blog csdn net xuanzhangran article details 54929988 如果是上传单张如下 点击上传图片按钮 上传本地 效果如图 1 原始图框 2 点击预览 弹出本地弹框 3
  • PB调用windows api删除文件夹及其子文件夹或子文件

    创建nvo folder对象 forward global type nvo folder from nonvisualobject end type type shfileopstruct from structure within nv
  • Java线程:线程的交互

    本文转载至 http lavasoft blog 51cto com 62575 99157 线程交互是比较复杂的问题 SCJP要求不很基础 给定一个场景 编写代码来恰当使用等待 通知和通知所有线程 一 线程交互的基础知识 SCJP所要求的