Java学习日记2 多线程通信

本文详细介绍了多线程环境下线程间的通信原理及实现方法,包括使用wait()、notify()和notifyAll()进行同步控制的基本示例,并进一步探讨了如何利用JDK1.5中的Lock和Condition对象来改进多线程通信机制。


多线程通信其实就是多个线程在操作同一个资源.只是操作的动作不同,

例如下图的多个线程对同一资源的操作也一样,比如线程1和线程2都是写入操作;

线程3和线程4都是读取操作.




虽然写入操作的线程1,2和读取操作的线程3,4已经同步,但是仍然存在写入操作执行2次,读取操作执行一次或者写入操作执行一次,读取操作执行2次,


这根本的原因是因为写入操作或读取操作的线程之间没有进行通讯,没有达到写一次读一次的目的.


如果 写入操作和读取操作各自自有一个线程,那么操作便没问题,持同种操作的如果是多线程话,线程之间也要进行通信才行..


wait()、notify()和notifyAll()这三个函数由java.lang.Object类提供,用于协调多个线程对共享数据的存取。


下面是一个写入读取的例子:

class Res
{
	private String name;
	private String sex;
	private boolean flag=false;
	public void set(String name,String sex)
	{
		this.name=name;
		this.sex=sex;
	}
	public void print()
	{
		System.out.println(name+"-----------"+sex);
	}
	public void setflag(boolean flag)
	{
		this.flag=flag;
	}
	public boolean getflag()
	{
		return flag;
	}

}

class input	implements Runnable
{
	private Res r;
	int x=0;
	input(Res r)
	{
		this.r=r;
	}
	public void run()
	{
		while(x<100)
		{
			synchronized(r)    //同步代码块
			{
				if(r.getflag()==true)
					try
					{
						r.wait();     //判断如果已经写入,写入线程则wait();wait()同时throw一个InterruptedException异常,父类Runnable
						}		  //不能处理该异常,不能throws只能内部trycatch处理.
					catch (InterruptedException e) 
					{
					}
				if(x%2==0)
					r.set("[Mike","male]");
				else
					r.set("[韩梅梅","性别女]");
				x++;
				r.setflag(true);
				r.notifyAll();			//该出需要用notifyAll();否则4个线程都会陷入wait()状态.
				System.out.print(Thread.currentThread().getName()+"|"+"input:"+x+"→");
			}
		}

	}
	
}

class output implements Runnable
{
	private Res r;
	output(Res r)
	{
		this.r=r;
	}
	public void run()
	{
		int x=0;
		while(x<100)
		{
			synchronized(r)
			{
				if(r.getflag()==false)
					try
					{
						r.wait();
					}
					catch (InterruptedException e)
					{
					}
				r.print();
				r.setflag(false);
				r.notifyAll();
				x++;
				System.out.println(Thread.currentThread().getName()+"|"+"output:"+x+"←┘");
			}
		}
	}

}






class WaitNotifyDemo
{
	public static void main(String[] args) 
	{
		Res r=new Res();
		input in=new input(r);
		output ot=new output(r);
		Thread t1=new Thread(in,"线程一");
		Thread t2=new Thread(in,"线程二");
		Thread t3=new Thread(ot,"线程三");
		Thread t4=new Thread(ot,"线程四");
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

notifyAll()目的是为了唤醒对方操作的线程.但这里notifyAll()把己方线程一并唤醒,怎么才能做到只唤醒对方线程呢?


JDK 1.5中提供了多线程升级解决方案,他将同步synchronized替换成了显示的Lock操作,将Object类中的方法wait() notify() notifyAll()替换成了Condition类的对象,

该类对象可通过Lock锁进行获取:

import java.util.concurrent.locks.*; //需导入,

Lock lock=new Lock();

Condition cdt1=lock.newCondition();

Condition cdt2=lock.newCondition();

该锁绑定了2个Condition对象,一个锁可以绑定多个Condition对象.

       Object方法        Condition方法  
  wait() await()
  notify()signal()
 notifyAll()signalAll()


每个Condition对象的唤醒和等待是唯一识别的,即cdt1.await(),只能被cdt1.signal()             ++|   或cdt1.signalAll()唤醒.|++此处不确定.

lock.lock()即便上锁,每次进入一个线程,直到该线程执行了lock.unlock();其他线程才可进入,

下面是一个面包房和学生的故事~~~

import java.util.concurrent.locks.*;

class resource
{
	Lock lock=new ReentrantLock();
	Condition con1=lock.newCondition();
	Condition con2=lock.newCondition();
	private String name;
	private boolean flag=false;
	private int num=1;
	private final int maxnum=3000;
	public void create(String name) throws InterruptedException
	{
		this.name=name;
		while(num<maxnum)
		{
			lock.lock();
			while(flag)
			{
				con1.await();
			}
			//	try{wait();}catch(InterruptedException e){System.out.println("ssss");}
				System.out.println(Thread.currentThread().getName()+"制造"+name+num);
				flag=true;
				con2.signal();   //生产线程生产一次,await(),唤醒消费线程,
			//	notifyAll();
			lock.unlock();
		}
	}
	public void consume() throws InterruptedException
	{
		while(num<=maxnum)
		{
			lock.lock();
			while(!flag)       //while使线程每次被唤醒都要判断flag
			{
				con2.await();
			}
			//	try{wait();}catch(InterruptedException e){}
				System.out.println(Thread.currentThread().getName()+"消费"+name+num);
				flag=false;
				num++;
				con1.signal();   
			//	notifyAll();
			lock.unlock();
		}
	}
}

class creator implements Runnable
{
	private resource r;
	creator(resource r)
	{
		this.r=r;
	}
	public void run()
	{
		try
		{
			r.create("面包:");
		}
		catch (InterruptedException e)
		{
		}
	}
}

class customer implements Runnable
{
	private resource r;
	customer(resource r)
	{
		this.r=r;
	}
	public void run()
	{
		try
		{
			r.consume();
		}
		catch (InterruptedException e)
		{
		}
	}
}

class CreatorCustomerDemo
{
	public static void main(String aaa[])
	{
		resource r=new resource();
		creator fac=new creator(r);
		customer cst=new customer(r);
		Thread t1=new Thread(fac,"生产者线程:面包房");
		Thread t2=new Thread(cst,"\t\t\t\t\t\t消费者线程:学生");
		t1.start();
		t2.start();
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值