java之12天 多线程 (一)

线程间通信问题
/**
 * 线程间通信问题
 *   其实就是多个线程在操作通过一个资源,但是操作的动作不同.
 * 
 * 同步的前提:
 * 1.必须要有两个或者两个以上的线程
 * 2.必须是多个线程使用同一个锁
 *
 * 等待唤醒机制 
 *  
 *  wait()
 *  notify()
 *  notifyAll();
 *  
 *  都使用在同步中,因为要对持有监视器的线程操作,所以要使用在 同步中,因为只有 同步才具有锁.
 *  
 *  为什么这些操作线程的方法要定义在Object类中呢?
 *  因为 这些方法 在操作同步中线程时,都必须要表示他们所操作线程的只有的锁.
 *  只有 同一个锁上的 被等待线程,可以被同一个锁上的notify唤醒
 *  不可以对不同锁中的线程进行唤醒.
 *  
 *  也就是,等待和唤醒 必须是同一个锁
 *  而锁可以是任意对象,所以可以被任意对象调用的 方法定义在 Object中
 *  
 *  
 *  
 */
class Resource{
	 String name;
	 String sex;
	 boolean flag=false;  //表示没有值
}

//复制
class Input implements Runnable{
	
	Resource r;
	Input(Resource r){
		this.r=r;
	}
	//Object obj=new Object();
	public void run(){
		int x=0;
		while(true){
			synchronized(r){ //obj -->this--> input.class(Output.class,InputOutputDemo.class)-->r
				if(r.flag){
					try {
						r.wait();  //线程运行的时候,程序会在内存中创建线程池,等待的线程会存在线程中 
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				if(x==0){
					r.name="mike";
					r.sex="man";
				}else{
					r.name="丽丽";
					r.sex="女女女女";
				}
				r.flag=true;
				r.notify();//唤醒 输出线程  通常会唤醒 线程池中 第一被等待的线程
			}
			x=(x+1)%2;
		}
	}
}

//取出后 然后输出
class Output implements Runnable{
	Resource r;
	Output(Resource r){
		this.r=r;
	}
	//Object obj=new Object();
	public void run(){
		while(true){
			synchronized(r){ //obj -->this--> input.class(Output.class,InputOutputDemo.class)-->r
				if(!r.flag)  
					try {
						r.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				System.out.println(r.name+"--------------"+r.sex);
				r.flag=false;
				r.notify();
			}
		}
	}
	
}

public class InputOutputDemo {
	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.必须要有两个或者两个以上的线程
 * 2.必须是多个线程使用同一个锁
 *
 * 等待唤醒机制 
 *  
 * 对上面的程序进行优化
 */
class Resource{
	 private String name;
	 private String sex;
	 private  boolean flag=false;  //表示没有值
	 
	 public synchronized void setValue(String name,String sex){
		 
		 if(flag){
			try{
				this.wait();  //线程运行的时候,程序会在内存中创建线程池,等待的线程会存在线程中 
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		 }
		 this.name=name;
		 this.sex=sex;
		 flag=true;
		 this.notify();
	 }
	 
	 public synchronized void out(){
		 if(!flag){
			try{
				this.wait();  //线程运行的时候,程序会在内存中创建线程池,等待的线程会存在线程中 
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		 }
		 System.out.println(name+"--------------"+sex);
		 flag=false;
		 this.notify();
	 }
	  
}


class Input implements Runnable{
	
	Resource r;
	Input(Resource r){
		this.r=r;
	}
	//Object obj=new Object();
	public void run(){
		int x=0;
		while(true){
			if(x==0){
				r.setValue("mike", "man");
			}else{
				r.setValue("莉莉", "女女");
			}
			x=(x+1)%2;
		}
	}
}

//取出后 然后输出
class Output implements Runnable{
	Resource r;
	Output(Resource r){
		this.r=r;
	}
	//Object obj=new Object();
	public void run(){
		while(true){
			r.out();
		}
	}
	
}

public class InputOutputDemo {
	public static void main(String[] args) {
		
		Resource r=new Resource();
		
		new Thread(new Input(r)).start();
		new Thread(new Output(r)).start();
		
		/*Input in=new Input(r);
		Output out=new Output(r);
		
		Thread t1=new Thread(in);
		Thread t2=new Thread(out);
		
		t1.start();
		t2.start();*/
	}

}


线程间通信 ,生产者 和消费者
/** 线程间通信 ,生产者 和消费者
 * 
 * 发现 上面的  等待唤醒机制 中 如果 线程数 超过过两个  使用  notify 就有问题了  
 *   原因 就是  当一个线程等待后  被其他线程 唤醒  就不会判断  flag 为真 为假 ,这样就会在某一时间段就会 生产多个商品  或者 消费多个商品
 *
 */
class Resouce{
	
	private String name;
	private int count=1;
	private boolean flag=false;
	
//	while(true){ //t1  t3  循环一次后发现 不一定 
		public synchronized void setValue(String name){
			while(flag)
				try {  
					this.wait();
				} catch (InterruptedException e) {// t1 (1等待--->5运行  )   t3  (2等待  --6 运行)
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			this.name=name+"...."+count++;
			System.out.println(Thread.currentThread().getName()+"....生产者...."+this.name);
			flag=true;
			//this.notify()  // 只唤醒线程中 最先等待那一个线程
			this.notifyAll();
		}
	//}
	
	public synchronized void out(){
		while(!flag)
			try {  
				this.wait();// t1 (3等待)   t3  (4等待)
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		System.out.println(Thread.currentThread().getName()+"...........消费者............."+this.name);
		flag=false;
		this.notifyAll();
	}
	
}
class Producer implements Runnable{
	
	Resouce r;
	Producer(Resouce r){
		this.r=r;
	}
	
	public void run(){
		while(true){
			r.setValue("+商品+");
		}
	}
}


class Consumer implements Runnable{
	
	Resouce r;
	Consumer(Resouce r){
		this.r=r;
	}
	
	public void run(){
		while(true){
			r.out();
		}
	}
}


public class ProducerConsumerDemo {

	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Resouce r=new Resouce();
		
		Producer p=new Producer(r);
		Consumer c=new Consumer(r);
		
		Thread t1=new Thread(p);
		Thread t2=new Thread(c);
		
		//使用 两个线程的时候  仿照 之前的  例子是没有问题,如果 超过两个线程后就会有问题了 
		Thread t3=new Thread(p);
		Thread t4=new Thread(c);
		
		t1.start();
		t2.start();
		
		//  因此 使用上  了 while  notifyAll   才解决这个问题  这是JDK1.5之前 的程序都这么干的 
		t3.start();
		t4.start();
	}


使用 JDK1.5的新特性 来优化上面的代码
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * JDK5.0 中提供了 多线程 升级解决方案
 * 将同步Synchronized 替换成  显示的 Lock机制
 * 将 Object 中的 wait notify  notifyall 替换成了 Condition对象中 await signal  signalAll
 * 
 * Condition 对象可以用  Lock 锁,进行获取
 * 
 * 在该实例中 实现了本方 只唤醒 对方的操作
 *
 */
class Resouce{
	
	private String name;
	private int count=1;
	private boolean flag=false;
	
	private Lock lock=new ReentrantLock();
	
	private Condition c_proc=lock.newCondition();  //声明 一个锁中  监视器对象
	private Condition c_cons=lock.newCondition();  //声明 一个锁中  监视器对象
	
	
	public  void setValue(String name) throws InterruptedException{
		lock.lock();   //synchronized
		try{
		while(flag)
			c_proc.await();   //this.wait()
			this.name=name+"...."+count++;
			System.out.println(Thread.currentThread().getName()+"....生产者...."+this.name);
			flag=true;
		}finally{  //释放锁的动作一定要执行
			//this.notify()  // 只唤醒线程中 最先等待那一个线程
			//this.notifyAll();
			c_cons.signal();   //只需要唤醒 消费者中的一个就可以了 不需要 All
		}
	}
	
	
	public  void out() throws InterruptedException{
		lock.lock();  //synchronized    一看就知道是同一个锁 是吧 呵呵 
		try{
			while(!flag)
			c_cons.await();  // this.wait();
			System.out.println(Thread.currentThread().getName()+"...........消费者............."+this.name);
			flag=false;
		}finally{
			//this.notifyAll();
			c_proc.signal(); // 唤醒生产者中的一个就可以了
		}
	}
	
}
//生产者
class Producer implements Runnable{
	
	Resouce r;
	Producer(Resouce r){
		this.r=r;
	}
	
	public void run(){
		while(true){
			try {
				r.setValue("+商品+");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

//消费者
class Consumer implements Runnable{
	
	Resouce r;
	Consumer(Resouce r){
		this.r=r;
	}
	
	public void run(){
		while(true){
			try {
				r.out();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}


public class ProducerConsumerDemo {

	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Resouce r=new Resouce();
		
		Producer p=new Producer(r);
		Consumer c=new Consumer(r);
		
		Thread t1=new Thread(p);
		Thread t2=new Thread(c);
		Thread t3=new Thread(p);
		Thread t4=new Thread(c);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}

你可能感兴趣的:(Condition,Lock,线程间通信,等待唤醒机制)