Java学习笔记46(多线程三:线程之间的通信)
多个线程在处理同一个资源,但是线程的任务却不相同,通过一定的手段使各个线程能有效地利用资源,
这种手段即:等待唤醒机制,又称作线程之间的通信
涉及到的方法:wait(),notify()
示例:
两个线程一个输入,一个输出
package demo;
public class Resource {
public String name;
public String sex;
}
输入线程:
package demo;
public class Input implements Runnable {
private Resource r = new Resource();
public void run() {
int i = 0;
while (true) {
if (i % 2 == 0) {
r.name = "张三";
r.sex = "男";
} else {
r.name = "李四";
r.sex = "女";
}
i++;
}
}
}
输出线程:
package demo;
public class Output implements Runnable {
private Resource r = new Resource();
public void run(){
while (true) {
System.out.println(r.name+"..."+r.sex);
}
}
}
测试类:
package demo;
public class ThreadDemo {
public static void main(String[] args) {
Input in = new Input();
Output out = new Output();
Thread tin = new Thread(in);
Thread tout = new Thread(out);
tin.start();
tout.start();
}
}
运行后却发现输出的都是null...null
因为输入线程和输出线程中创建的Resource对象使不同的
解决null问题:
package demo;
public class Input implements Runnable {
private Resource r;
public Input(Resource r){
this.r = r;
}
public void run() {
int i = 0;
while (true) {
if (i % 2 == 0) {
r.name = "张三";
r.sex = "男";
} else {
r.name = "李四";
r.sex = "女";
}
i++;
}
}
}
package demo;
public class Output implements Runnable {
private Resource r;
public Output(Resource r){
this.r = r;
}
public void run(){
while (true) {
System.out.println(r.name+"..."+r.sex);
}
}
}
package demo;
public class ThreadDemo {
public static void main(String[] args) {
Resource r = new Resource();
Input in = new Input(r);
Output out = new Output(r);
Thread tin = new Thread(in);
Thread tout = new Thread(out);
tin.start();
tout.start();
}
}
运行后又发现了另一个问题:
输出中含有:张三...女或者李四...男,性别出错
发生原因:
赋值完张三和男后,继续赋值李四和女,这时候还未还得及赋值女,就进入了输出线程,这时候就会输出李四...男
于是想到加上同步:
public void run() {
int i = 0;
while (true) {
synchronized (this) {
if (i % 2 == 0) {
r.name = "张三";
r.sex = "男";
} else {
r.name = "李四";
r.sex = "女";
}
i++;
}
}
}
public void run() {
while (true) {
synchronized (this) {
System.out.println(r.name + "..." + r.sex);
}
}
}
然而问题并没有解决:
原因:
这里的同步失去了作用,用到的不是一个锁
解决办法:
使用一个共同的锁即可
public void run() {
int i = 0;
while (true) {
synchronized (r) {
if (i % 2 == 0) {
r.name = "张三";
r.sex = "男";
} else {
r.name = "李四";
r.sex = "女";
}
i++;
}
}
}
public void run() {
while (true) {
synchronized (r) {
System.out.println(r.name + "..." + r.sex);
}
}
}
这时候就是正常的输出了
但是还是存在一个问题,我们希望的是张三和李四交错出现,一个张三一个李四,现在依然是随机出现的,大片的张三或李四
解决办法:
先让input线程赋值,然后让output线程输出,并且让输入线程等待,不允许再赋值李四,等待输出张三结束后,再允许李四赋值,依次下去
输入线程也需要同样的方式,输出完后要等待
这时候就需要用到等待唤醒机制:
输入:赋值后,执行方法wait()永远等待
输出:打印后,再输出等待之前,唤醒输入notify(),自己再wait()永远等待
输入:被唤醒后,重新赋值,必须notify()唤醒输出的线程,自己再wait()等待
依次循环下去
代码实现:
package demo;
public class Resource {
public String name;
public String sex;
public boolean flag = false;
}
package demo;
public class Input implements Runnable {
private Resource r;
public Input(Resource r) {
this.r = r;
}
public void run() {
int i = 0;
while (true) {
synchronized (r) {
if (r.flag) {
try {
r.wait();
} catch (Exception e) {
}
}
if (i % 2 == 0) {
r.name = "张三";
r.sex = "男";
} else {
r.name = "李四";
r.sex = "女";
}
r.flag = true;
r.notify();
}
i++;
}
}
}
package demo;
public class Output implements Runnable {
private Resource r;
public Output(Resource r) {
this.r = r;
}
public void run() {
while (true) {
synchronized (r) {
if (!r.flag) {
try {
r.wait();
} catch (Exception e) {
}
}
System.out.println(r.name + "..." + r.sex);
r.flag = false;
r.notify();
}
}
}
}
package demo;
public class ThreadDemo {
public static void main(String[] args) {
Resource r = new Resource();
Input in = new Input(r);
Output out = new Output(r);
Thread tin = new Thread(in);
Thread tout = new Thread(out);
tin.start();
tout.start();
}
}
这时候就是张三李四交错输出了
完成
Java学习笔记46(多线程三:线程之间的通信)的更多相关文章
- Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)
多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ...
- Java多线程编程-线程之间的通信
转载自:这里 学习了基础的线程知识 看到了 线程之间的通信 线程之间有哪些通信方式呢? 1.同步 这里讲的同步是指多个线程通过synchronized关键字这种方式来实现线程间的通信. public ...
- 20145316许心远《Java学习笔记》第三周总结
20145316许心远<Java程序设计>第3周学习总结 教材学习内容总结 一.定义类: 类定义时使用class关键字 如果要将x绑定到新建的对象上,可以使用"="制定 ...
- 【原】Java学习笔记032 - 多线程
package cn.temptation; public class Sample01 { public static void main(String[] args) { /* * [进程]:正在 ...
- Java学习笔记:多线程(二)
与线程生命周期相关的方法: sleep 调用sleep方法会进入计时等待状态,等待时间到了,进入就绪状态. yield 调用yield方法会让别的线程执行,但是不确保真正让出.较少使用,官方注释都说 ...
- java之等待唤醒机制(线程之间的通信)
线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同.比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消 ...
- 10月9日Android学习笔记:活动与服务之间的通信
最近在照着<第一行代码>这本书来学安卓,顺便记下笔记.主要的内容是Android中服务的第二种启动方式,通过活动绑定服务来启动服务,实现活动与服务之间的通信. 一. 首先创建一个服务类 p ...
- Java学习笔记:多线程(一)
Java中线程的五种状态: 新建状态(New) 就绪状态(Runnable) 运行状态(Running) 阻塞状态(Blocked) 凋亡状态(Dead) 其中阻塞状态(Blocked)又分为三种: ...
- Java 学习笔记(11)——多线程
Java内部提供了针对多线程的支持,线程是CPU执行的最小单位,在多核CPU中使用多线程,能够做到多个任务并行执行,提高效率. 使用多线程的方法 创建Thread类的子类,并重写run方法,在需要启动 ...
随机推荐
- jmeter 实现 mysql 存储过程
Callable Statement:存储过程语句.可以在一个脚本里实现增删改查. 实现方法: 1)首先创建一个存储过程 2)然后执行这个存储过程
- JS event loop
一.为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. Java ...
- Java中的包装数据类型
基本类型 包装器类型 boolean Boolean char Character int Integer byte Byte short Short long Long float Float do ...
- keil mdk5安装
- 十二、Decorator 装饰器模式
设计: 代码清单: Display public abstract class Display { public abstract int getColumns(); public abstract ...
- 每月IT摘录201903
技术 1.在开发高并发系统时,有很多手段来保护系统,如缓存.降级.限流等.缓存可以提升系统的访问速度,降级可以暂时屏蔽掉非核心业务,使得核心业务不受影响.限流的目的是通过对并发访问进行限速,一旦达到一 ...
- 8-13、Python 散列复习
1.{} 输入是花括号 myCat = { 'size':'fat', 'color':'gray', 'disposition':'loud'} 键:值 myCat['size'] = fat ...
- IDEA在运行Mybatis时找不到路径
idea的默认是不加载java文件下的所以我们要手动添加,加载java文件到pom文件下,在build中添加 <resources> <resource> <direct ...
- Python开发【第五篇】:模块
递归的案例:阶乘 1*2*3*4*5*6*7- def func(num): if num == 1: return 1 return num * func(num - ...
- 【开发工具】secureCRT的使用
总结自己平时使用secureCRT中遇到的问题 1.安装 2.secureCRT设置标签显示远程主机ip地址