首页 > 代码库 > JAVA学习第二十六课(多线程(五))- 多线程间的通信问题

JAVA学习第二十六课(多线程(五))- 多线程间的通信问题

一、线程间的通信


实例代码:

需求是:输入一个姓名和性别后,就输出一个姓名和性别

class Resource
{
	String name;
	String sex ;
}
class Input implements Runnable
{
	Resource r;
	Input(Resource r)
	{
		this.r = r;
	}
	public void run()
	{
		int x = 0;
		while(true)
		{
			synchronized (r) 
			{
				if(x==0)
				{
					r.name = "BLF";
					r.sex = "male";
				}
				else {
					r.name = "妮妮妮妮";
					r.sex = "female";
				}
				x = (++x)%2;
			}
		}
	}
}

class Output implements Runnable
{
	Resource r;
	public Output(Resource r) {
		// TODO Auto-generated constructor stub
		this.r = r;
	}
	public void run() 
	{
		while(true)
		{
			synchronized (r) //输入和输出都是应用同一个锁
			{
				System.out.println(r.name+"..."+r.sex);
			}
		}
	}
}
public class Main 
{
	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();
	}
}

上述代码虽然解决了,多线程处理同一资源问题,但是出现了一个问题就是,打印很多一个人名和性别后再打印另一个,无法实现交替输出,原因:输入线程获取执行权后,不会执行一次,输入姓名和性别,输入线程还拥有执行权,一直赋值,等到切换到输出执行权后,输出最后输入的姓名和性别,但是输出线程也不会只输出一次,一直输出,所以出现打印很多同一姓名和性别的问题


二、线程的等待/唤醒机制:

用一个boolean值判断是否有数据,有就不放,没有就放

输入线程执行时判断是否有数据,有,就释放执行权,再释放执行资格,进入冻结状态,输出线程执行,输出后boolean值置为false


Input:
         if(flag)//有值
           wait();//当前冻结,切换输出线程
         flag = true;
         notify();

Output:
         if(!flag)
       wait();
         flag = false;//flag置为假,输出完毕
      notify();//唤醒输入线程

等待/唤醒机制:

方法:

1.wait();//使线程进入冻结状态,CPU释放执行权和执行资格,被wait()的线程会被存储到线程池中
2.notify();//唤醒线程池中的任意的一个线程
3.notifyAll();//唤醒所有线程,使之处于运行状态或临时阻塞状态,总之,使其具备执行资格

这些方法必须定义在同步中,这些方法是用于操作线程状态的方法,所以必须明确在哪个锁上的线程

(wait()A锁的线程,只能用A锁的notify唤醒A锁的线程。)

了解:而wait()等方法是定义在Object类中的,这些方法是监视器的方法,而监视器呢,就可以理解为锁,控制哪个锁所属下的线程,而锁又可以是任意的,而所有的类都是继承于Object类的,所以wait()等类是定义在Object里


下述代码就解决了上述代码的问题,实现了输入输出线程的交替执行

class Resource extends Object
{
	String name;
	String sex ;
	boolean flag = false;
}
class Input implements Runnable
{
	Resource r;
	Input(Resource r)
	{
		this.r = r;
	}
	public void run()
	{
		int x = 0;
		while(true)
		{
			synchronized (r) 
			{
				if(r.flag)
				{
					try {
						r.wait();
					} catch (Exception e) {
						// TODO: handle exception
					}
					
				}
					
				if(x==0)
				{
					r.name = "BLF";
					r.sex = "male";
				}
				else {
					r.name = "妮妮妮妮";
					r.sex = "female";
				}
				r.flag = true;
				r.notify();
				x = (++x)%2;
			}
		}
	}
}

class Output implements Runnable
{
	Resource r;
	public Output(Resource r) {
		// TODO Auto-generated constructor stub
		this.r = r;
	}
	public void run() 
	{
		
		while(true)
		{
			synchronized (r) 
			{
				if(!r.flag)
				{
					try {
						r.wait();
					} catch (Exception e) {
						// TODO: handle exception
					}
				}
					
					
				System.out.println(r.name+"..."+r.sex);
				r.flag = false;
				r.notify();
			}
		}
	}
}
public class Main 
{
	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();
	}
}

三:等待唤醒机制代码优化


资源中的成员为了可控,应该为私有的,对外提供方法

所以同步的操作,就在Resource类中执行,应用同步函数

class Resource extends Object
{
	private String name;
	private String sex ;
	private boolean flag = false;
	public synchronized void set(String name,String sex) 
	{
		// TODO Auto-generated constructor stub
		if(flag)
		{
			try {
				this.wait();
			} catch (Exception e) {
				// TODO: handle exception
				
			}
		}
		
		this.name = name;
		this.sex = sex;
		
		flag = true;
		this.notify();
	}
	public synchronized void out()
	{
		if(!flag)
		{
			try {
				this.wait();
			} catch (Exception e) {
				// TODO: handle exception
			}
			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 x = 0;
		while(true)
		{
			if(x==0)
			{
				r.set("BLF", "male"); 				
			}
			else 
			{
				r.set("妮妮妮妮", "female");
			}			
			x = (++x)%2;
			
		}
	}
}
class Output implements Runnable
{
	Resource r;
	public Output(Resource r) {
		// TODO Auto-generated constructor stub
		this.r = r;
	}
	public void run() 
	{
		while(true)
		{
			r.out();
		}
	}
}
public class Main 
{
	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();
	}
}


JAVA学习第二十六课(多线程(五))- 多线程间的通信问题