Java学习个人备忘录之线程间的通信
线程间通讯
多个线程在处理同一资源,但是任务却不同.
class Resource
{
String name;
String sex;
} //输入
class Input implements Runnable
{
Resource r;
Input(Resource r)
{
this.r = r;
}
public void run()
{
int i = 0;
while(true)
{
synchronized(r) //保证两个线程用同一个锁
{
if (i==0)
{
r.name = "mike";
r.sex = "nan";
}
else
{
r.name = "丽丽";
r.name = "女女女女女女女女女";
}
x = (x+1)%2;
}
}
}
} //输出
class Output implements Runnable
{
Resource r;
Output(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
synchronized(r) //保证两个线程用同一个锁
{
System.out.println(r.name+"....."+r.sex);
}
}
}
} class ResourceDemo
{
public static void main(String[] args)
{
//创建资源
Resource r = new Resource();
//创建任务
Input in = new Input(r);
Output out = new Output(r);
//创建线程
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
//开启线程
t1.start();
t2.start();
}
}
但是这样会造成大量的才重复, 没有交替性。
等待唤醒机制
涉及的方法:
1. wait(): 让线程处于冻结状态, 被wait的线程会被存储到线程池中.
2. notify(): 唤醒线程池中一个线程(任意)
3. notifyAll(): 唤醒线程池中的所有线程.
这些方法都必须定义在同步中,
因为这些方法都是用于操做线程状态的方法.
必须要明确到底操做的是哪个锁上的线程.
为什么操做线程的方法wait notify notifyAll定义在了Object类中.
因为这些方法时监视器的方法, 坚持其其实就是锁.
锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中的.
class Resource
{
String name;
String sex;
boolean flag = false;
} //输入
class Input implements Runnable
{
Resource r;
Input(Resource r)
{
this.r = r;
}
public void run()
{
int i = 0;
while(true)
{
synchronized(r) //保证两个线程用同一个锁
{
if (r.flag)
{
r.wait();
}
if (i==0)
{
r.name = "mike";
r.sex = "nan";
}
else
{
r.name = "丽丽";
r.name = "女女女女女女女女女";
}
r.flag = true;
r.notify(); //唤醒对方
x = (x+1)%2;
}
}
}
} //输出
class Output implements Runnable
{
Resource r;
Output(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
synchronized(r) //保证两个线程用同一个锁
{
if (!r.flag)
{
r.wait();
}
System.out.println(r.name+"....."+r.sex);
r.flag = false;
r.notify(); //唤醒对方
}
}
}
} class ResourceDemo2
{
public static void main(String[] args)
{
//创建资源
Resource r = new Resource();
//创建任务
Input in = new Input(r);
Output out = new Output(r);
//创建线程
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
//开启线程
t1.start();
t2.start();
}
}
上面代码的优化
class Resource
{
private String name; //这里要私有化
private String sex;
boolean flag = false;
public synchronized void set(String name,String sex) //对数据要可控化
{
if (this.flag)
try{this.wait();}catch(InterruptedException e){}
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
public synchronized void out()
{
if (this.flag)
try{this.wait();}catch(InterruptedException e){}
System.out.println(name+"....."+sex);
flag = false;
this.notify();
}
} //输入
class Input implements Runnable
{
Resource r;
Input(Resource r)
{
this.r = r;
}
public void run()
{
int i = 0;
while(true)
{
if (i==0)
{
r.set("mike","nan");
}
else
{
r.set"丽丽","女女女女女女女女女");
}
x = (x+1)%2;
}
}
} //输出
class Output implements Runnable
{
Resource r;
Output(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
} class ResourceDemo3
{
public static void main(String[] args)
{
//创建资源
Resource r = new Resource();
//创建任务
Input in = new Input(r);
Output out = new Output(r);
//创建线程
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
//开启线程
t1.start();
t2.start();
}
}
多生产者多消费者问题
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name)
{
if (flag)
try{this.wait();}catch(InterruptedException e){}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+".....生产者....."+this.name);
flag = true;
notify();
}
public synchronized void out()
{
if (!flag)
try{this.wait();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+".....消费者....."+this.name);
flag = false;
notify();
}
} class Producer implements Runnable
{
private Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while (true)
{
r.set("烤鸭");
}
}
} class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
} class ProducerConsumerDemo
{
public static void main(String[] args)
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}
但是这样会出现安全隐患, 从这4个线程上看, 一共分了两组, t0和t1一组, t2和t3一组, 当t1 t2 t3 睡眠时, t0出来后再次唤醒t1, 这时t1是不用判断的if条件的,直接向下继续执行. 这样就又进行了"生产烤鸭", 所以出现了安全隐患. 解决办法: 将两个if 换成 while, 这样在t1醒来的时候会继续判断flag是否为真. 但是这样又会出现死锁现象, 因为t1判断flag时, flag为真, 这时t1会再次等待,这时4个线程都进入等待状态---死锁!!
解决办法1
将notify换成notifyAll, 这样就一定会唤醒对方的线程,同时自己方的线程因为while循环出不去.
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name)
{
while (flag)
try{this.wait();}catch(InterruptedException e){}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+".....生产者....."+this.name);
flag = true;
notifyAll();
}
public synchronized void out()
{
while (!flag)
try{this.wait();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+".....消费者....."+this.name);
flag = false;
notifyAll();
}
} class Producer implements Runnable
{
private Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while (true)
{
r.set("烤鸭");
}
}
} class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
} class ProducerConsumerDemo
{
public static void main(String[] args)
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}
if判断标记只有一次, 会导致不该运行的线程运行了, 出现了数据错误的情况. while判断标记, 解决了线程获取执行权后, 是否要运行。
notify: 只能唤醒一个线程, 如果本方唤醒了本方, 就没有意义, 而且while判断标记notify会导致死锁. notifyAll解决了, 本方线程一定会唤醒对方线程.
解决办法2:
JDK1.5新特征的解决办法--Lock
可以看出来, 上面的解决方法会造成多次无用的判断, 这会降低效率,可以用这面的方法解决.
Lock l = new ReentrantLock();
void show()
{
l.lock(); //获取锁
code...
l.unlock(); //释放锁
}
jdk1.5以后将同步和锁封装成了对象.
并将操作锁的隐式方法定义到了该对象中,
将隐式动作变成了显示动作.
但是如果执行的代码抛出了异常, 这样代码就会一直持有锁,不释放,所以要如下
Lock l = new ReentrantLock();
void show()
{
l.lock(); //获取锁
try
{
code...
}
finally
{
l.unlock(); //释放锁
}
}
import java.util.concurrent.locks.*
class Resource
{
private String name;
private int count = 1;
private boolean flag = false; Lock l = new ReentrantLock();//因为Lock是java.util.concurrent.locks包中的类, 所以要先导入包. public void set(String name) //这里的同步就可以去掉了
{
l.lock(); //在这里加上锁
try
{
while (flag)
try{this.wait();}catch(InterruptedException e){}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+".....生产者....."+this.name);
flag = true;
notifyAll();
}
finally
{
l.unlock();
}
}
public void out()
{
l.lock();
try
{
while (!flag)
try{this.wait();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+".....消费者....."+this.name);
flag = false;
notifyAll();
}
finally
{
l.unlock();
}
}
} class Producer implements Runnable
{
private Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while (true)
{
r.set("烤鸭");
}
}
} class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
} class ProducerConsumerDemo
{
public static void main(String[] args)
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}
解决办法3:
JDK1.5新特征的解决办法--Condition
Condition在底层上是这样实现的:
interface Condition
{
await();
signal();
signalAll();
}
所以要这样实现, 如下:
Lock l = new ReectrantLock();
Condition c1 = l.newCondition();
Condition c2 = l.newCondition();
import java.util.concurrent.locks.*
class Resource
{
private String name;
private int count = 1;
private boolean flag = false; //创建一个锁对象.
Lock l = new ReentrantLock();//因为Lock是java.util.concurrent.locks包中的类, 所以要先导入包. //通过已有的锁获取该锁上的监视器对象.
Condition con = l.newCondition(); public void set(String name) //这里的同步就可以去掉了
{
l.lock(); //在这里加上锁
try
{
while (flag)
// try{this.wait();}catch(InterruptedException e){} //这里用con.await()替换
try{con.await();}catch(InterruptedException e){}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+".....生产者....."+this.name);
flag = true;
// notifyAll(); //这里用con.signalAll() 替换
con.signalAll();
}
finally
{
l.unlock();
}
}
public void out()
{
l.lock();
try
{
while (!flag)
// try{this.wait();}catch(InterruptedException e){} //这里用con.await()替换
try{con.await();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+".....消费者....."+this.name);
flag = false;
// notifyAll(); //这里用con.signalAll() 替换
con.signalAll();
}
finally
{
l.unlock();
}
}
} class Producer implements Runnable
{
private Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while (true)
{
r.set("烤鸭");
}
}
} class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
} class ProducerConsumerDemo2
{
public static void main(String[] args)
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}
其实解决办法3和解决办法2没有太大的区别.并没有真的运用了1.5的新特征。
解决办法4
这个解决办法才真正的运用到了1.5的新特征。
import java.util.concurrent.locks.*
class Resource
{
private String name;
private int count = 1;
private boolean flag = false; //创建一个锁对象.
Lock l = new ReentrantLock();//因为Lock是java.util.concurrent.locks包中的类, 所以要先导入包. //通过已有的锁获取该锁上的监视器对象.
// Condition con = l.newCondition(); //通过已有的锁获取两组监视器, 一组监视生产者, 一组监视消费者.
Condition producer_con = l.newCondition();
Condition consumer_con = l.newCondition(); public void set(String name) //这里的同步就可以去掉了
{
l.lock(); //在这里加上锁
try
{
while (flag)
try{producer_con.await();}catch(InterruptedException e){} //这里只让生产者等待
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+".....生产者....."+this.name);
flag = true;
consumer_con.signal(); //这里直接唤醒消费者
}
finally
{
l.unlock();
}
}
public void out()
{
l.lock();
try
{
while (!flag)
try{consumer_con.await();}catch(InterruptedException e){} //这里只让消费者等待
System.out.println(Thread.currentThread().getName()+".....消费者....."+this.name);
flag = false;
producer_con.signalAll(); //这里只唤醒生产者
}
finally
{
l.unlock();
}
}
} class Producer implements Runnable
{
private Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while (true)
{
r.set("烤鸭");
}
}
} class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
} class ProducerConsumerDemo2
{
public static void main(String[] args)
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}
Java学习个人备忘录之线程间的通信的更多相关文章
- Java核心知识点学习----多线程并发之线程间的通信,notify,wait
1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...
- java多线程详解(6)-线程间的通信wait及notify方法
Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New) ...
- Java 多线程(七) 线程间的通信——wait及notify方法
线程间的相互作用 线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务. Object类中相关的方法有两个notify方法和三个wait方法: http://docs.oracle.com/ ...
- 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题
调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...
- Java多线程学习(五)线程间通信知识点补充
系列文章传送门: Java多线程学习(二)synchronized关键字(1) Java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Java多 ...
- 【转】Java学习---线程间的通信
[原文]https://www.toutiao.com/i6572378564534993415/ 两个线程间的通信 这是我们之前的线程. 执行效果:谁抢到资源,谁运行~ 实现线程交替执行: 这里主要 ...
- 【转】Java学习:Java中的线程之线程间的通信
hello各位小伙伴 今天我们来搞一下 线程之间的通信 ( • ̀ω•́ )✧ 让线程按照我们的想法来执行 两个线程间的通信 这是我们之前的线程. 执行效果:谁抢到资源,谁运行~ 实现线程交替执行: ...
- Java学习笔记-多线程-创建线程的方式
创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...
- Java多线程中线程间的通信
一.使用while方式来实现线程之间的通信 package com.ietree.multithread.sync; import java.util.ArrayList; import java.u ...
随机推荐
- 用VMWare搭建服务器集群不能上外网的三种模式下对应解决办法
前言 决心要花费宝贵时间写下这篇心得,是因为从昨天晚上到今天上午被这个VMWare模拟搭建的服务器集群不能上外网的问题搞得很心烦,最后决定跟它杠上了!上午还通过远程连接得到了“空白”同学的帮助,在此表 ...
- 第2章 jQuery选择器
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- H5混合开发进阶之inspect调试
h5界面嵌套在原生app内部的时候,需要调用原生的方法,传递数据.中间难以调试代码,. 用google的 inspect调试.查看数据的传输方式. 1.adb连接正常,打开手机USB调试 2.第一次使 ...
- git创建使用1https://blog.csdn.net/Hanani_Jia/article/details/77950594
这篇文章是我自己写的关于GitHub的内容,从我刚听到这个直到设置成功每一步都有详细的步骤来解释,其中有一些截图或者代码来自于网上. 首先,我先对GitHub来一个简单的介绍,GitHub有一个很强大 ...
- [转]Javascript removeChild()删除节点及删除子节点的方法(同样适用于jq)
Javascript removeChild()删除节点及删除子节点的方法 这篇文章主要介绍了Javascript removeChild()删除节点及删除子节点的方法的相关资料,需要的朋友可以参考下 ...
- 爬虫-windows下安装Scrapy及scrapy模块介绍
一:安装wheel wheel介绍 二:安装twisted twisted是由python编写的一款基于事件驱动的网络引擎,使用twisted模块将python的异步请求(异步模型介绍)成为可能且简 ...
- 第4天 Java基础语法
第4天 Java基础语法 今日内容介绍 流程控制语句(switch) 数组 流程控制语句 选择结构switch switch 条件语句也是一种很常用的选择语句,它和if条件语句不同,它只能针对某个表达 ...
- php7+apache2.4+mysql 环境配置(window环境)
最近,小主从事PHP开发.特将最近如何搭建php7的过程记录在此!希望有需要,可以借鉴!( 电脑必须win7 sp1以上, .netframework4 ) Windows7安装php7,Win7+p ...
- HyperLedger Fabric 1.4 基础环境搭建(7)
学习了前面几章理论知识后,本章开始介绍实践操作,先介绍Fabric基础环境搭建,采用的操作系统为Centos 7 64位,依次介绍Docker安装.Docker-Compose安装.GO语言环境安装. ...
- 快排(golang实现) 递归方法
递归方法,逻辑简洁清晰.这个算法还是很重要的,需要重点记忆理解,面试经常考手写.据说是与傅里叶变换等并称“20世纪十大算法”.https://blog.csdn.net/v_JULY_v/articl ...