Java学习笔记之线程间的通信

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

*/

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();
	}
}


posted @ 2015-01-28 10:43  Y_zr  阅读(169)  评论(0编辑  收藏  举报