`
高军威
  • 浏览: 180661 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

多线程(线程间通信问题)

阅读更多
代码1线程不安全:
/**
 * 线程间通信
 * 其实就是多线程在操作同一个资源
 * 但是操作的动作不同
 * */
class Res
{
	String name;
	String sex;
}
class Input implements Runnable
{
	private Res res;
	Input(Res res)
	{
		this.res =res;
	}
	@Override
	public void run() {
		int x=0;
		while (true) {
			if(x==0)
			{
				res.name = "mike";
				res.sex = "man";
			}
			else
			{
				res.name = "丽丽";
				res.sex = "女女女女女";
			}
			x = (x+1)%2;
		}
	}
}
class Output implements Runnable
{
	private Res res;
	Output(Res res)
	{
		this.res =res;
	}
	@Override
	public void run() {
		while (true) {
			System.out.println(res.name+"......"+res.sex);
		}
	}
}

class Test
{
	public static void main(String[] args) {
		Res res = new Res();
		
		Input i = new Input(res);
		Output o = new Output(res);
		
		Thread t1 = new Thread(i);
		Thread t2 = new Thread(o);
		
		t1.start();
		t2.start();
	}
}


运行结果:
线程不安全


代码2线程安全:
class Res
{
	String name;
	String sex;
}
class Input implements Runnable
{
	private Res res;
	Input(Res res)
	{
		this.res =res;
	}
	@Override
	public void run() {
		int x=0;
		while (true) {
			synchronized (res) {
				if(x==0)
				{
					res.name = "mike";
					res.sex = "man";
				}
				else
				{
					res.name = "丽丽";
					res.sex = "女女女女女";
				}
				x = (x+1)%2;
			}
		}
	}
}
class Output implements Runnable
{
	private Res res;
	Output(Res res)
	{
		this.res =res;
	}
	@Override
	public void run() {
		while (true) {
			synchronized (res) {
				System.out.println(res.name+"......"+res.sex);
			}
		}
	}
}

class Test
{
	public static void main(String[] args) {
		Res res = new Res();
		
		Input i = new Input(res);
		Output o = new Output(res);
		
		Thread t1 = new Thread(i);
		Thread t2 = new Thread(o);
		
		t1.start();
		t2.start();
	}
}


运行结果:
多线程安全;


需求:放入一个值输出一个值;(多线程通讯:等待唤醒机制)
代码3:
/**
 * 线程间通信
 * 其实就是多线程在操作同一个资源
 * 但是操作的动作不同
 * 
 * wait();
 * notify();
 * notifyAll();
 * 
 * 都使用在同步中,因为要对持有监视器(锁)的线程操作。
 * 所以要使用在同步中,应为只有同步才具有锁。
 * 
 * 为什么这些操作线程的方法要定义Object类中呢?
 * 因为这些方法在操作同步中线程时,都必须要标识他们做操作线程只有的锁。
 * 只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。
 * 不可以对不同锁中的线程进行唤醒。
 * 
 * 也就是说,等待和唤醒必须是同一个锁。
 * 
 *而锁可以是任意对象,所以可以任意对象调用的方法定义在Object类中。
 * */
class Res
{
	String name;
	String sex;
	boolean flag=false;
}
class Input implements Runnable
{
	private Res res;
	Input(Res res)
	{
		this.res =res;
	}
	@Override
	public void run() {
		int x=0;
		while (true) {
			synchronized (res) {
				if(res.flag)
				{
					try {
						res.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				if(x==0)
				{
					res.name = "mike";
					res.sex = "man";
				}
				else
				{
					res.name = "丽丽";
					res.sex = "女女女女女";
				}
				x = (x+1)%2;
				res.flag=true;
				res.notify();
			}
		}
	}
}
class Output implements Runnable
{
	private Res res;
	Output(Res res)
	{
		this.res =res;
	}
	@Override
	public void run() {
		while (true) {
			synchronized (res) {
				if(!res.flag){
					try {
						res.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println(res.name+"......"+res.sex);
				res.flag = false;
				res.notify();
			}
		}
	}
}


class Test
{
	public static void main(String[] args) {
		Res res = new Res();
		
		Input i = new Input(res);
		Output o = new Output(res);
		
		Thread t1 = new Thread(i);
		Thread t2 = new Thread(o);
		
		t1.start();
		t2.start();
	}
}


运行结果:
符合需求;


以上代码优化:
代码4:
class Res
{
	private String name;
	private String sex;
	private boolean flag=false;
	
	public synchronized void set(String name,String sex) {
		if(flag)
		{
			try { this.wait(); } catch (InterruptedException e) 
			{ e.printStackTrace();}
		}
		this.name = name;
		this.sex = sex;
		flag = true;
		this.notify();
	}
	public synchronized void out() {
		if(!flag)
		{
			try { this.wait(); } catch (InterruptedException e) 
			{ e.printStackTrace();}
		}
		System.out.println(this.name+"......"+this.sex);
		flag = false;
		this.notify();
	}
	
	
}
class Input implements Runnable
{
	private Res res;
	Input(Res res)
	{
		this.res =res;
	}
	@Override
	public void run() {
		int x=0;
		while (true) {
			if(x==0)
				res.set("mike", "man");
			else
				res.set("丽丽", "女女女女女");
			x = (x+1)%2;
		}
	}
}
class Output implements Runnable
{
	private Res res;
	Output(Res res)
	{
		this.res =res;
	}
	public void run() {
		while (true) {
			res.out();
		}
	}
}

class Test
{
	public static void main(String[] args) {
		Res res = new Res();
		
		new Thread(new Input(res)).start();
		new Thread(new Output(res)).start();
	}
}


生产消费模式:
多个生产者,多个消费者:
代码5:
/**
 * 资源
 * */
class Resource
{
	private String name;
	private int count=1;
	private boolean flag = false;
	
	public synchronized void set(String name) {
		while(flag)
		{
			try {wait();//放弃执行权 注意:当被唤醒后,获得执行权接着往下执行,并持有共同锁
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.name = name+"--"+count++;
		
		System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
		flag = true;
		notify();
	}
	public synchronized void out() {
		while(!flag)
		{
			try {wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name);
		flag = false;
		notify();
	}
}
/**
 * 生产者
 * */
class Producer implements Runnable
{
	private Resource res;
	
	Producer(Resource res)
	{
		this.res = res;
	}
	public void run() {
		while (true) {
			res.set("+商品+");
		}
	}
}
/**
 * 消费者
 * */
class Consumer implements Runnable
{
	private Resource res;
	
	Consumer(Resource res)
	{
		this.res = res;
	}
	public void run() {
		while (true) {
			res.out();
		}
	}
}
/**
 * 测试
 * */
class Test
{
	public static void main(String[] args) {
		Resource r = new Resource();
		
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);
		
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(pro);
		Thread t3 = new Thread(con);
		Thread t4 = new Thread(con);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}


运行结果:
没有反应了,原因是 这几个线程都放弃执行权了;


解决以上问题:
将notify()方法,修改为notifyAll()(比较通用的方式);
运行结果图:
运行结果OK了;
问题1:但是 notifyAll唤醒了所有线程包括本方的线程,要怎样使生产者线程运行完唤醒消费者线程而不是全都唤醒?


用Lock来替代sysynchronized :

代码4使用lock实现方式:
代码6使用lock实现多线程 生产消费模式 一对一:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 资源
 * */
class Resource
{
	private String name;
	private int count=1;
	private boolean flag = false;
	
	private Lock lock = new ReentrantLock();
	private Condition condition = lock.newCondition();
	
	public void set(String name) throws InterruptedException {
		lock.lock();
		try
		{
			while(flag)
			{
				condition.await();
			}
			this.name = name+"--"+count++;
			
			System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
			flag = true;
			condition.signal();//唤醒 下一个线程
		}
		finally
		{
			lock.unlock();//释放资源
		}
	}
	public  void out() throws InterruptedException {
		lock.lock();
		try
		{
			while(!flag)
				condition.await();
			System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name);
			flag = false;
			condition.signal();//唤醒 下一个线程
		}
		finally
		{
			lock.unlock();//释放资源
		}
	}
}
/**
 * 生产者
 * */
class Producer implements Runnable
{
	private Resource res;
	
	Producer(Resource res)
	{
		this.res = res;
	}
	public void run() {
		while (true) {
			try {
				res.set("+商品+");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
/**
 * 消费者
 * */
class Consumer implements Runnable
{
	private Resource res;
	
	Consumer(Resource res)
	{
		this.res = res;
	}
	public void run() {
		while (true) {
			try {
				res.out();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
/**
 * 测试
 * */
class Test
{
	public static void main(String[] args) {
		Resource r = new Resource();
		
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);
		
		Thread t1 = new Thread(pro);
		Thread t4 = new Thread(con);
		
		t1.start();
		t4.start();
	}
}


代码5的修改版使用lock实现方式:
代码7使用lock实现多线程生产消费模式 多对多:
代码7:
/**
 * 资源
 * */
class Resource
{
	private String name;
	private int count=1;
	private boolean flag = false;
	
	private Lock lock = new ReentrantLock();
	private Condition condition = lock.newCondition();
	
	public void set(String name) throws InterruptedException {
		lock.lock();
		try
		{
			while(flag)
				condition.await();
			this.name = name+"--"+count++;
			
			System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
			flag = true;
			condition.signalAll();//唤醒所有使用共享对象的线程
		}
		finally
		{
			lock.unlock();//释放资源
		}
	}
	public  void out() throws InterruptedException {
		lock.lock();
		try
		{
			while(!flag)
				condition.await();
			System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name);
			flag = false;
			condition.signalAll();
		}
		finally
		{
			lock.unlock();//释放资源
		}
	}
}
/**
 * 生产者
 * */
class Producer implements Runnable
{
	private Resource res;
	
	Producer(Resource res)
	{
		this.res = res;
	}
	public void run() {
		while (true) {
			try {
				res.set("+商品+");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
/**
 * 消费者
 * */
class Consumer implements Runnable
{
	private Resource res;
	
	Consumer(Resource res)
	{
		this.res = res;
	}
	public void run() {
		while (true) {
			try {
				res.out();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
/**
 * 测试
 * */
class Test
{
	public static void main(String[] args) {
		Resource r = new Resource();
		
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);
		
		Thread t1 = new Thread(pro);t1.start();
		Thread t3 = new Thread(con);t3.start();
		
		Thread t2 = new Thread(pro);t2.start();
		Thread t4 = new Thread(con);t4.start();
	}
}


现在使用lock 的新特性解决代码5中的问题1;

一个lock上可以有多个condition :
代码8:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 资源
 * JDK1.5 中提供了多线程升级解决方案
 * 将synchronized替换成Condition对象。
 * 将Object中的wait,notify,nottfyAll,替换了Condition对象。
 * 该对象可以使用Lock锁进行获取。
 * 该示例中,实现了本方只唤醒对方的操作。
 * */
class Resource
{
	private String name;
	private int count=1;
	private boolean flag = false;
	
	private Lock lock = new ReentrantLock();
	private Condition condition_pro = lock.newCondition();//锁条件
	private Condition condition_con = lock.newCondition();//
	
	public void set(String name) throws InterruptedException {
		lock.lock();
		try
		{
			while(flag)
				condition_pro.await();
			this.name = name+"--"+count++;
			
			System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
			flag = true;
			condition_con.signal();//唤醒某个线程
		}
		Finally
		{
			lock.unlock();//释放资源 一定要执行
		}
	}
	public  void out() throws InterruptedException {
		lock.lock();
		try
		{
			while(!flag)
				condition_con.await();
			System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name);
			flag = false;
			condition_pro.signal();
		}
		finally
		{
			lock.unlock();//释放资源
		}
	}
}
/**
 * 生产者
 * */
class Producer implements Runnable
{
	private Resource res;
	
	Producer(Resource res)
	{
		this.res = res;
	}
	public void run() {
		while (true) {
			try {
				res.set("+商品+");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
/**
 * 消费者
 * */
class Consumer implements Runnable
{
	private Resource res;
	
	Consumer(Resource res)
	{
		this.res = res;
	}
	public void run() {
		while (true) {
			try {
				res.out();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
/**
 * 测试
 * */
class Test
{
	public static void main(String[] args) {
		Resource r = new Resource();
		
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);
		
		Thread t1 = new Thread(pro);t1.start();
		Thread t3 = new Thread(con);t3.start();
		
		Thread t2 = new Thread(pro);t2.start();
		Thread t4 = new Thread(con);t4.start();
	}
}


Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
条件(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式 释放相关的锁,并挂起当前线程,就像 Object.wait 做的那样。
Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。
分享到:
评论

相关推荐

    多线程之间的线程通信

    4. **管道(Pipe)**和**套接字(Socket)**:这些是进程间通信(IPC)的方法,也可以用于线程间通信。例如,在服务器-客户端模型中,通过套接字进行通信,线程可以在同一进程中模拟网络通信,从而更好地理解线程通信的...

    MFC线程间通信

    然而,当一个应用程序中有多个线程运行时,它们可能需要共享数据或协调工作,这就涉及到线程间通信(Inter-Thread Communication,简称ITC)。MFC(Microsoft Foundation Classes)库,作为Windows平台上C++开发的...

    基于SOCKET和多线程的应用程序间通信技术的研究.pdf

    《基于SOCKET和多线程的应用程序间通信技术的研究》一文深入探讨了在不同程序之间采用SOCKET和多线程技术进行数据通信的方法。本文将详细解析标题和描述中的核心知识点,包括SOCKET和多线程的基本原理,以及它们在...

    VC利用管道和多线程实现进程间通信

    VC利用管道和多线程实现进程间通信 VC++环境下利用管道和线程实现进程间通信的技术是指在Windows操作系统中,使用Visual C++语言,通过创建管道和线程来实现进程之间的通信。这种技术可以在不同的进程之间实现信息...

    VC多线程例程七及图解文档(线程间通信)

    本文将深入探讨“VC多线程例程七”,重点介绍线程间通信这一关键概念,并结合源码分析,以MultiThread7项目为例进行详细讲解。 线程是操作系统分配CPU时间的基本单位,一个进程中可以有多个线程并行运行。在VC++中...

    C#线程间通信

    采用的是C#的Winform开发,提供了两种线程交互的方式。 第一:在主线程中开启两个子线程,子线程用事件方式来进行通信。对于主线程的控件操作采用的是delegate委托的方式,避免主线程假死。 第二:采用的是...

    Java的多线程-线程间的通信.doc

    在Java多线程编程中,线程间的通信是非常重要的概念,用于协调多个并发执行的任务。线程的状态转换是理解线程通信的基础,主要包括四个状态:新(New)、可执行(Runnable)、死亡(Dead)和停滞(Blocked)。新状态...

    Qt线程之间通信、线程和进程之间通信实例

    本实例将深入探讨Qt如何实现线程间通信以及线程与进程间通信,并提供简单易懂的代码示例。 一、Qt线程间通信 Qt通过信号和槽机制,使得线程间的通信变得直观且易于理解。信号是对象状态变化的通知,而槽是响应这些...

    线程间通信方式3:消息传递方式

    在多线程编程中,线程间通信是一个关键的概念,用于协调不同线程之间的操作,确保数据的一致性和正确性。本示例“线程间通信方式3:消息传递方式”着重介绍了通过消息传递实现线程间的通信。下面将详细阐述这种通信...

    多线程线程间通信,可用于控制线程内部函数

    多线程线程间通信,可用于控制线程内部函数,做处理......................................................

    创建线程及线程间通信

    接下来,我们关注线程间通信。线程通信是线程协作完成任务的关键,它允许线程之间交换数据或同步操作。一种常见的通信机制是“生产者-消费者”模型,其中生产者线程生成数据,而消费者线程消费这些数据。在没有适当...

    MFC多线程间消息通信工程案例

    线程间通信的一种常见方法是使用`WM_USER`到`WM_USER+1000`之间的自定义消息,这些消息可以携带特定的数据,比如计算结果或者进度信息。在MFC中,可以通过`ON_MESSAGE`宏在消息映射表中注册这些自定义消息的处理函数...

    线程间通信的定义及全局变量的方法

    本文将重点探讨线程间的通信方式,特别是通过全局变量进行线程间通信的方法以及为了解决数据竞争问题而引入的同步和互斥机制。 首先,线程间通信指的是在同一个进程中的多个线程之间交换信息或数据的过程。由于线程...

    多线程之间消息通信

    线程间通信(Inter-Thread Communication,ITC)是多线程编程中的核心概念,它允许线程共享数据、交换状态或者同步执行。在Windows操作系统中,VC++(Visual C++)提供了一些API和机制来支持线程间的通信。其中,一...

    多线程套接字间通信

    在IT领域,多线程套接字间通信是网络编程中的一个重要主题,特别是在设计高性能、高并发的应用程序时。本文将深入探讨C++语言中如何利用SOCKET API进行多线程间的通信,这对于初学者来说具有重要的学习价值。 首先...

    C#,socket(多线程)通信

    利用多线程实现C#中socket网络通信模块,具体最大承受多少个客户端还不是很清楚,但是20个绝对没问题

    Java多线程技术在网络通信系统中的应用.pdf

    总结来说,Java多线程技术在网络通信系统中的应用包括了线程间通信的原理、多线程实现网络通信的原理、线程安全及同步控制的有效途径,以及网络通信编程中的Socket类实现。掌握这些技术要点,对于进行高效、稳定、...

    彻底明白Java的多线程-线程间的通信.doc

    为了实现真正的并发,我们需要使用更复杂的同步机制,如线程同步或线程间通信。 接着,我们来看如何在Java中实现多线程。有两种主要方式:继承`Thread`类和实现`Runnable`接口。 1. **继承Thread类**: 当一个类...

    qt 中 多线程tcp通信

    在Qt框架下实现多线程TCP通信是一种常见且高效的方法,尤其在处理实时性要求高、数据量大的网络应用中。以下将详细讲解Qt中如何进行多线程TCP通信,以及涉及的关键知识点。 首先,标题"qt 中 多线程tcp通信"表明...

Global site tag (gtag.js) - Google Analytics