`

线程间通讯学习【五】

    博客分类:
  • Java
阅读更多
线程间通讯,当有多个生产者、消费者时,容易导致的问题。


一、当只有两个线程,一个生产、一个消费的时候,数据是没有问题的,如下:
package com.zzl.thread;

class MyResource{
	private String name;
	private int number = 1;
	private boolean flag = false;
	
	public synchronized void set(String name){
		if(flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.name = name +"......"+ number++;
		System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
		this.flag = true;
		this.notify();
	}
	
	public synchronized void print(){
		if(!flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName()+"---------消费者---------"+this.name);
		this.flag = false;
		this.notify();
	}
	
}

class Producer implements Runnable{
	private MyResource r;
	public Producer(MyResource r){
		this.r = r;
	}
	@Override
	public void run() {
		while(true){
			r.set("苹果");
		}
		
	}
	
}

class Consumer implements Runnable{
	private MyResource r;
	public Consumer(MyResource r){
		this.r = r;
	}
	@Override
	public void run() {
		while(true){
			r.print();
		}
	}
	
}




public class ProducerConsumerDemo {
	
	public static void main(String[] args) {
		MyResource r = new MyResource();
		Producer p = new Producer(r);
		Consumer c = new Consumer(r);
		Thread t1 = new Thread(p);
		Thread t2 = new Thread(c);
		t1.start();
		t2.start();
	}

}

运行效果:
Thread-1---------消费者---------苹果......40535
Thread-0...生产者...苹果......40536
Thread-1---------消费者---------苹果......40536
Thread-0...生产者...苹果......40537
Thread-1---------消费者---------苹果......40537
Thread-0...生产者...苹果......40538
Thread-1---------消费者---------苹果......40538
Thread-0...生产者...苹果......40539
Thread-1---------消费者---------苹果......40539
Thread-0...生产者...苹果......40540
Thread-1---------消费者---------苹果......40540
Thread-0...生产者...苹果......40541
Thread-1---------消费者---------苹果......40541
Thread-0...生产者...苹果......40542
Thread-1---------消费者---------苹果......40542
Thread-0...生产者...苹果......40543
Thread-1---------消费者---------苹果......40543
Thread-0...生产者...苹果......40544
Thread-1---------消费者---------苹果......40544








二、当有两个生产者、消费者时,数据出现了问题:
package com.zzl.thread;

class MyResource{
	private String name;
	private int number = 1;
	private boolean flag = false;
	
	public synchronized void set(String name){
		if(flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.name = name +"......"+ number++;
		System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
		this.flag = true;
		this.notify();
	}
	
	public synchronized void print(){
		if(!flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName()+"---------消费者---------"+this.name);
		this.flag = false;
		this.notify();
	}
	
}

class Producer implements Runnable{
	private MyResource r;
	public Producer(MyResource r){
		this.r = r;
	}
	@Override
	public void run() {
		while(true){
			r.set("苹果");
		}
		
	}
	
}

class Consumer implements Runnable{
	private MyResource r;
	public Consumer(MyResource r){
		this.r = r;
	}
	@Override
	public void run() {
		while(true){
			r.print();
		}
	}
	
}




public class ProducerConsumerDemo {
	
	public static void main(String[] args) {
		MyResource r = new MyResource();
		Producer p = new Producer(r);
		Consumer c = new Consumer(r);
		Thread t1 = new Thread(p);
		Thread t2 = new Thread(p);
		Thread t3 = new Thread(c);
		Thread t4 = new Thread(c);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}

运行效果(第五行、第六行都为生产者):
Thread-0...生产者...苹果......19803
Thread-2---------消费者---------苹果......19803
Thread-0...生产者...苹果......19804
Thread-2---------消费者---------苹果......19804
Thread-0...生产者...苹果......19805
Thread-1...生产者...苹果......19806
Thread-3---------消费者---------苹果......19806
Thread-1...生产者...苹果......19807
Thread-3---------消费者---------苹果......19807
Thread-1...生产者...苹果......19808
Thread-3---------消费者---------苹果......19808
Thread-1...生产者...苹果......19809
Thread-3---------消费者---------苹果......19809







三、如果为多个生产者和消费者,修改如下: if判断改为while判断,当线程被唤醒的时候,都要去判断一下flag; 并把notify 改为notifyAll唤醒线程,不管生产者还是消费者都唤醒。
package com.zzl.thread;

class MyResource{
	private String name;
	private int number = 1;
	private boolean flag = false;
	
	public synchronized void set(String name){
		while(flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.name = name +"......"+ number++;
		System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
		this.flag = true;
		this.notifyAll();
	}
	
	public synchronized void print(){
		while(!flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName()+"---------消费者---------"+this.name);
		this.flag = false;
		this.notifyAll();
	}
	
}

class Producer implements Runnable{
	private MyResource r;
	public Producer(MyResource r){
		this.r = r;
	}
	@Override
	public void run() {
		while(true){
			r.set("苹果");
		}
		
	}
	
}

class Consumer implements Runnable{
	private MyResource r;
	public Consumer(MyResource r){
		this.r = r;
	}
	@Override
	public void run() {
		while(true){
			r.print();
		}
	}
	
}




public class ProducerConsumerDemo {
	
	public static void main(String[] args) {
		MyResource r = new MyResource();
		Producer p = new Producer(r);
		Consumer c = new Consumer(r);
		Thread t1 = new Thread(p);
		Thread t2 = new Thread(p);
		Thread t3 = new Thread(c);
		Thread t4 = new Thread(c);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}

运行效果:
Thread-0...生产者...苹果......20549
Thread-2---------消费者---------苹果......20549
Thread-1...生产者...苹果......20550
Thread-3---------消费者---------苹果......20550
Thread-0...生产者...苹果......20551
Thread-2---------消费者---------苹果......20551
Thread-1...生产者...苹果......20552
Thread-3---------消费者---------苹果......20552
Thread-0...生产者...苹果......20553
Thread-2---------消费者---------苹果......20553
Thread-1...生产者...苹果......20554
Thread-3---------消费者---------苹果......20554
分享到:
评论

相关推荐

    JAVA100例之实例64 JAVA线程间通讯

    在"JAVA100例之实例64 JAVA线程间通讯"这个主题中,我们将深入探讨Java中实现线程间通信的几种主要方法。 1. **共享数据**:最直观的线程间通信方式是通过共享内存空间,即共享变量。只要对共享变量的操作是线程...

    界面线程工作线程之间的通讯

    学习这部分内容可以帮助开发者深入理解多线程编程,特别是如何在不违反线程安全规则的情况下进行界面与后台的通信。 总结来说,"界面线程工作线程之间的通讯"是一个关键的编程主题,涉及多线程同步、消息队列和线程...

    在Visual C++中利用自定义消息实现线程间通讯C++源代码程序小实例

    通过分析和学习这个代码,你可以更深入地理解如何在Visual C++中利用自定义消息进行线程间通信。 要注意的是,线程间通信还涉及同步问题,比如使用`Mutex`、`Semaphore`或`Event`等同步对象来避免数据竞争和死锁。...

    Qt多线程通讯

    在“Qt多线程通讯”DEMO中,主线程可能创建了一个`QThread`实例,并启动它。接着,一个工作对象(可能是自定义的QObject派生类)被移动到子线程中。这个工作对象可能会有一个接收参数的槽函数,用于处理主线程传递...

    Android AIDL线程间通讯样例项目

    总结,这个"Android AIDL线程间通讯样例项目"是学习和理解Android进程间通信机制的一个宝贵资源。通过分析和实践项目中的`Apdu_Client_Test`和`Apdu_Main_Test`,开发者可以深入掌握AIDL的工作方式,以及如何在实际...

    多线程之间通讯5.rar

    在IT领域,多线程是程序设计中的一个重要概念,特别是在并发执行和性能优化时。当一个应用程序需要...通过阅读“多线程之间通讯.docx”文档和观看“第五节(join()用法).mp4”视频,可以更深入地学习这些概念和技巧。

    多线程串口通讯实例源码

    - 从提供的"多线程串口通讯实例"源码中,我们可以看到如何结合上述知识点,实现一个同时读取Excel数据和进行串口通信的程序。 - 源码可能包括一个主线程负责用户界面交互,一个或多个子线程用于串口通信,确保数据...

    多线程同步和通讯完整示例

    synchronized关键字提供了基本的线程同步,而wait-notify机制和Lock接口则提供了更高级的线程通讯和控制手段。在实际开发中,根据具体需求选择合适的同步策略,可以提高程序的效率和正确性。通过学习和实践...

    多线程UDP通讯例子

    在实际应用中,我们还需要考虑线程同步问题,比如使用互斥锁(mutex)防止多个线程同时访问共享资源,使用条件变量(condition variable)来协调线程间的等待和唤醒等。此外,为了保证程序的健壮性,异常处理和错误...

    多线程事件对象通讯

    通过分析这些源码,我们可以学习到如何在实际项目中应用事件对象进行线程间的通信。 总之,多线程事件对象通讯是Windows编程中的重要概念,通过理解和掌握这一技术,开发者可以编写出更加高效和可靠的多线程程序。...

    csharp多线程示例(全)

    通过学习和实践这些C#多线程示例,开发者能够更好地掌握如何在应用程序中有效地使用多线程,提高程序的性能和用户体验。在实际项目中,应根据任务特性和系统需求选择合适的线程管理策略,确保程序的稳定性和效率。

    disruptor高性能Java线程间通讯库

    Disruptor是一款由LMAX交易所开发的开源Java框架,它专为高并发环境下的线程间通信设计,致力于提供极低的延迟和高效的性能。在Java开发中,尤其是在需要处理大量并发请求的系统中,Disruptor是一个重要的工具,它...

    tcp多线程socket通讯

    自己闲暇时候写的socket多线程通讯模型,代码虽然比较简单,但是比较容易扩展,麻雀虽小,五脏俱全。

    [233]多线程串口通讯例子,vc#开发的例子。代码比较简洁。但是有参考价值.zip上位机开发VC串口学习资料源码下载

    但是有参考价值.zip上位机开发VC串口学习资料源码下载[233]多线程串口通讯例子,vc#开发的例子。代码比较简洁。但是有参考价值.zip上位机开发VC串口学习资料源码下载[233]多线程串口通讯例子,vc#开发的例子。代码比较...

    c#编写串口通讯代码 多线程实现

    以上知识点涵盖了C#中多线程串口通讯的基本原理和实践技巧,通过学习和掌握这些内容,开发者可以编写出高效、稳定的串口通信程序。在实际项目中,还需要根据具体需求和硬件环境调整和完善代码。

    异步和多线程socket通讯

    本文将深入探讨"异步和多线程socket通讯"这一主题,基于提供的描述和标签,我们将讨论如何利用多线程和异步机制来提升socket通信的效率和响应性。 首先,Socket是一种在应用程序与网络服务之间建立连接的接口,它...

    多线程串口通讯实例

    而"多线程串口通讯实例_622"可能是一个源码文件,包含了完整的VC++项目代码,供开发者参考和学习。 总结来说,这个实例为开发者提供了一个实践多线程串口通信的范例,通过VC++编程语言,展示了如何在多个串口通信中...

    易语言线程通信

    通过阅读和理解这部分代码,我们可以深入学习如何在易语言中实现高效的线程间通信。 总的来说,易语言线程通信涉及到了线程的创建、消息的发送与接收等关键操作。理解和掌握这些知识点,能够帮助开发者编写出更加...

    多线程UDP通讯程序源代码

    本资源提供的"多线程UDP通讯程序源代码"就是一个很好的实践案例,它涉及到计算机网络中的用户数据报协议(UDP)和多线程编程技术。以下是关于这两个关键知识点的详细解释: 1. **用户数据报协议(UDP)**: UDP是...

    多线程编程学习资料(适合中级读者)

    "多线程编程之三——线程间通讯"是多线程编程中的一大重点。线程间通讯是为了实现不同线程之间的协作,通常包括共享数据、信号量、事件、消息队列等机制。这部分将详细解释这些通信方式的使用和注意事项,比如如何...

Global site tag (gtag.js) - Google Analytics