线程间通讯
多个线程在处理同一资源,但是任务却不同.

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学习个人备忘录之线程间的通信的更多相关文章

  1. Java核心知识点学习----多线程并发之线程间的通信,notify,wait

    1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...

  2. java多线程详解(6)-线程间的通信wait及notify方法

    Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New) ...

  3. Java 多线程(七) 线程间的通信——wait及notify方法

    线程间的相互作用 线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务. Object类中相关的方法有两个notify方法和三个wait方法: http://docs.oracle.com/ ...

  4. 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题

    调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...

  5. Java多线程学习(五)线程间通信知识点补充

    系列文章传送门: Java多线程学习(二)synchronized关键字(1) Java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Java多 ...

  6. 【转】Java学习---线程间的通信

    [原文]https://www.toutiao.com/i6572378564534993415/ 两个线程间的通信 这是我们之前的线程. 执行效果:谁抢到资源,谁运行~ 实现线程交替执行: 这里主要 ...

  7. 【转】Java学习:Java中的线程之线程间的通信

    hello各位小伙伴 今天我们来搞一下 线程之间的通信 ( • ̀ω•́ )✧ 让线程按照我们的想法来执行 两个线程间的通信 这是我们之前的线程. 执行效果:谁抢到资源,谁运行~ 实现线程交替执行: ...

  8. Java学习笔记-多线程-创建线程的方式

    创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...

  9. Java多线程中线程间的通信

    一.使用while方式来实现线程之间的通信 package com.ietree.multithread.sync; import java.util.ArrayList; import java.u ...

随机推荐

  1. MySQL索引的使用及注意事项

    索引是存储引擎用于快速找到记录的一种数据结构.索引优化应该是对查询性能优化最有效的手段了.索引能够轻易将查询性能提高几个数量级,"最优"的索引有时比一个"好的" ...

  2. (Linux学习笔记一:压缩)[20180209]

    学习笔记一:压缩 2015年2月5日 上午 10:23 压缩命令 压缩文件的扩展名大多是*.tar.*.tar.gz.*.tgz.*.gz.*.Z.*.bz2 常见的压缩命令gzip与bzip2,其中 ...

  3. 如何防止index.html首页被篡改

    近期发现公司网站首页文件经常被篡改为indax.php或indax.html,导致网站的功能无法正常使用,百度搜索关键词,在显示结果中点击公司网站,打开后跳转到别的网站上去了,尤其我们在百度做的推广, ...

  4. Java学习笔记二十二:Java的方法重写

    Java的方法重写 一:什么是方法的重写: 如果子类对继承父类的方法不满意,是可以重写父类继承的方法的,当调用方法时会优先调用子类的方法. 语法规则 返回值类型.方法名.参数类型及个数都要与父类继承的 ...

  5. tomcat搭建https服务(非自签发)

    平时做自己的web demo基本上都是用http协议进行访问. 但是正式情况基本上都是https进行访问,所以掌握https的配置是很关键的. 需要准备的材料: 一台可以可以外网访问的远程服务器 to ...

  6. .Net 面试题 汇总(六)

    一.填空题 1.面向对象的语言具有(继承)性.(多态)性.(封装)性. 2.能用foreach遍历访问的对象需要实现 (IEnumberable)接口或声明(GetEnumberator)方法的类型. ...

  7. Java 高级应用编程 第一章 工具类

    一.Java API Java API简介 1.API (Application Programming Interface) 应用程序接口 2.Java中的API,就是JDK提供的各种功能的Java ...

  8. 20145202mc《计算机病毒》实践3

    网站检测 http://www.virscan.org/ lab01-02.exe lab01-03.exe 分析这两个文件是否加壳了: Lab01-02.exe lab01-03.exe 查看两个样 ...

  9. c++动态库封装及调用(2、windows下动态库创建)

    DLL即动态链接库(Dynamic-Link Libaray)的缩写,相当于Linux下的共享对象.Windows系统中大量采用了DLL机制,甚至内核的结构很大程度依赖与DLL机制.Windows下的 ...

  10. libevent学习三(Getting an event_base)

    1.一个event_base持有了一系列的事件,并监控和决定哪些事件需要激活, 2.每一个event_base背后都有一个支持其工作的方法(诸如select,poll,epoll,kquene...) ...