线程笔记2--线程的通信(生产者与消费者案例分析)
2017-11-12 16:21
453 查看
线程通信
1、线程通信:不同的线程执行不同的任务,如果这些任务有某种关系,线程之间必须能够通信,协调完成工作,线程通信是相互间状态的切换。
2、线程通信-wait和notify方法介绍:
java.lang.Object类提供类两类用于操作线程通信的方法.
wait():执行该方法的线程对象释放同步锁,JVM把该线程存放到等待池中,等待其他的线程唤醒该线程(失去CPU和锁).
notify:执行该方法的线程随机唤醒在等待池中等待的任意一个线程,把线程转到锁池中等待.
notifyAll():执行该方法的线程唤醒在等待池中等待的所有的线程,把线程转到锁池中等待.
!注意:上述方法只能被同步监听锁对象来调用,否则报错IllegalMonitorStateException...
3、生产者与消费者案例分析:
为什么生产者不直接把数据给消费者,而是先把数据存储到共享资源中,然后,消费者再从共享资源中取出数据,再消费.
在这里体现了面向对象的设计理念:低耦合.
高(紧)耦合:
直接使用生产者把肉包子给消费者,那么生产者中得存在消费者的引用,同理,消费者要消费生产者生产的肉包子,消费者中也得存在生产者对象的引用.
低(松)耦合:使用一个中间对象,屏蔽了生产者和消费者直接的数据交互.
Demo:
public class ThreadDemo1 {
public static void main(String[] args) {
Product pro = new Product();
Producers ps = new Producers(pro);
Salers ss = new Salers(pro);
Thread th1 = new Thread(ps);
Thread th2 = new Thread(ss);
th1.start();
th2.start();
}
}
class Product {
private int id;
private String name;
private boolean flag;
private int i;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
//produce
synchronized public void produce() {
if (this.isFlag()) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.setName("小火炮");
this.setId(++i);
System.out.println("produce: "+this.getName()+this.getId());
this.setFlag(true);
this.notify();
}
//sale
synchronized public void sale() {
if (!this.isFlag()) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("sale: "+this.getName()+this.getId());
this.setFlag(false);
this.notify();
}
}
class Producers implements Runnable{
private Product pro;
public Producers(Product pro) {
this.pro = pro;
}
@Override
public void run() {
while(true) {
pro.produce();
}
}
}
class Salers implements Runnable{
private Product pro;
public Salers(Product pro) {
this.pro = pro;
}
@Override
public void run() {
while(true) {
pro.sale();
}
}
}
4、线程通信-使用Lock和Condition接口:
wait和notify方法,只能被同步监听锁对象来调用,否则报错IllegalMonitorStateException.
那么现在问题来了,Lock机制根本就没有同步锁了,也就没有自动获取锁和自动释放锁的概念.
因为没有同步锁,所以Lock机制不能调用wait和notify方法.
解决方案:Java5中提供了Lock机制的同时提供了处理Lock机制的通信控制的Condition接口.
1):使用Lock机制取代synchronized
代码块和synchronized
方法.
2):使用Condition接口对象的await,signal,signalAll方法取代Object类中的wait,notify,notifyAll方法.
Demo:
多个生产者和消费者案例:
//产品:
public class Product {
private String name;
private String country;
private boolean isEmpty = true;
Lock lock = new ReentrantLock();
Condition cd_p = lock.newCondition();
Condition cd_s = lock.newCondition();
public void pro(String n, String c){
lock.lock();
try {
while(!isEmpty){
cd_p.await();
}
name = n;
Thread.sleep(10);
country = c;
isEmpty = false;
cd_s.signalAll();
} catch (Exception e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
public void sale(){
lock.lock();
try {
while(isEmpty){
cd_s.await();
}
Thread.sleep(10);
System.out.println(this.name+"---"+this.country);
isEmpty = true;
cd_p.signalAll();
} catch (Exception e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
1、线程通信:不同的线程执行不同的任务,如果这些任务有某种关系,线程之间必须能够通信,协调完成工作,线程通信是相互间状态的切换。
2、线程通信-wait和notify方法介绍:
java.lang.Object类提供类两类用于操作线程通信的方法.
wait():执行该方法的线程对象释放同步锁,JVM把该线程存放到等待池中,等待其他的线程唤醒该线程(失去CPU和锁).
notify:执行该方法的线程随机唤醒在等待池中等待的任意一个线程,把线程转到锁池中等待.
notifyAll():执行该方法的线程唤醒在等待池中等待的所有的线程,把线程转到锁池中等待.
!注意:上述方法只能被同步监听锁对象来调用,否则报错IllegalMonitorStateException...
3、生产者与消费者案例分析:
为什么生产者不直接把数据给消费者,而是先把数据存储到共享资源中,然后,消费者再从共享资源中取出数据,再消费.
在这里体现了面向对象的设计理念:低耦合.
高(紧)耦合:
直接使用生产者把肉包子给消费者,那么生产者中得存在消费者的引用,同理,消费者要消费生产者生产的肉包子,消费者中也得存在生产者对象的引用.
低(松)耦合:使用一个中间对象,屏蔽了生产者和消费者直接的数据交互.
Demo:
public class ThreadDemo1 {
public static void main(String[] args) {
Product pro = new Product();
Producers ps = new Producers(pro);
Salers ss = new Salers(pro);
Thread th1 = new Thread(ps);
Thread th2 = new Thread(ss);
th1.start();
th2.start();
}
}
class Product {
private int id;
private String name;
private boolean flag;
private int i;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
//produce
synchronized public void produce() {
if (this.isFlag()) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.setName("小火炮");
this.setId(++i);
System.out.println("produce: "+this.getName()+this.getId());
this.setFlag(true);
this.notify();
}
//sale
synchronized public void sale() {
if (!this.isFlag()) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("sale: "+this.getName()+this.getId());
this.setFlag(false);
this.notify();
}
}
class Producers implements Runnable{
private Product pro;
public Producers(Product pro) {
this.pro = pro;
}
@Override
public void run() {
while(true) {
pro.produce();
}
}
}
class Salers implements Runnable{
private Product pro;
public Salers(Product pro) {
this.pro = pro;
}
@Override
public void run() {
while(true) {
pro.sale();
}
}
}
4、线程通信-使用Lock和Condition接口:
wait和notify方法,只能被同步监听锁对象来调用,否则报错IllegalMonitorStateException.
那么现在问题来了,Lock机制根本就没有同步锁了,也就没有自动获取锁和自动释放锁的概念.
因为没有同步锁,所以Lock机制不能调用wait和notify方法.
解决方案:Java5中提供了Lock机制的同时提供了处理Lock机制的通信控制的Condition接口.
1):使用Lock机制取代synchronized
代码块和synchronized
方法.
2):使用Condition接口对象的await,signal,signalAll方法取代Object类中的wait,notify,notifyAll方法.
Demo:
多个生产者和消费者案例:
//产品:
public class Product {
private String name;
private String country;
private boolean isEmpty = true;
Lock lock = new ReentrantLock();
Condition cd_p = lock.newCondition();
Condition cd_s = lock.newCondition();
public void pro(String n, String c){
lock.lock();
try {
while(!isEmpty){
cd_p.await();
}
name = n;
Thread.sleep(10);
country = c;
isEmpty = false;
cd_s.signalAll();
} catch (Exception e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
public void sale(){
lock.lock();
try {
while(isEmpty){
cd_s.await();
}
Thread.sleep(10);
System.out.println(this.name+"---"+this.country);
isEmpty = true;
cd_p.signalAll();
} catch (Exception e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
//消费者: public class Consumer extends Thread{ Product p = null; public Consumer(Product p) { this.p = p; } public void run() { for (int i = 0; i <25; i++) { p.sale(); } } }
//生产者: public class Producer extends Thread{ Product p = null; public Producer(Product p) { this.p = p; } public void run() { for(int i = 0; i <25; i++){ if(i%2==0){ p.pro("火炮", "中国"); }else{ p.pro("香肠", "四川"); } } } }
//测试类 public class Test { public static void main(String[] args) { Product p = new Product(); new Consumer(p).start(); new Consumer(p).start(); new Producer(p).start(); new Producer(p).start(); } }
相关文章推荐
- Java SE学习笔记:线程通信、生产者与消费者案例、线程状态(线程的生命周期)、线程操作、Condition类
- [知了堂学习笔记]_线程通信(生产者和消费者模式)
- 黑马程序员自学笔记————多线程 线程间通信之生产者消费者问题;
- 【多线程】_线程操作案例——生产者和消费者笔记
- 黑马程序员_Java基础_线程间通信,生产者消费者案例,jdk1.5锁机制,守护线程
- 线程通信案例(消费者和生产者)
- Java线程间通信问题分析(生产者消费者模型)
- JAVA笔记14__多线程共享数据(同步)/ 线程死锁 / 生产者与消费者应用案例 / 线程池
- JAVA学习笔记(1)_____模拟线程通信之生产者消费者问题
- 第23章 java线程通信——生产者/消费者模型案例
- JavaSE 多线程 线程间通信 生产者与消费者案例
- 【多线程】_线程操作案例——生产者和消费者笔记
- 多线程—03—线程间通信、生产者消费者
- 线程通信,生产者消费者问题(Java)
- 多线程基础3-死锁、线程通信、生产者消费者模式
- 黑马程序员——生产者消费者问题之线程间通信
- 线程之间通信之消费者生产者问题
- Java基础复习:线程通信—生产者消费者改进
- 线程间通信(生产者与消费者问题)
- java线程通信--生产者消费者问题