j2se -----线程---生产者与消费者

-------------------------------------------------------------------------
生产者和消费者问题----java
我们现在生产的是信息,有两种信息的生产
信息种类1: name = 李兴华  content = Java讲师
信息种类2: name = "mldn"  content = "www.mldnJava.com"
先看一个问题例子:
class Info{
	private String name = "李兴华";
	private String content = "Java讲师";
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
}

class Producer implements Runnable{
	private Info info = null;
	public Producer(Info info){
		this.info = info;
	}
	 
	public void run(){
		boolean isPersonInfo = false; //这个工厂生产两种东西,而且是交替生产,注意,这种东西与锁有着巨大的区别,因为他允许多个线程访问它,虽然在第一次大家都进入isPersonInfo=false的里面,但是必然有一个线程先执行完,执行完后就改变了isPersonInfo=true,那么显然这对另外一个线程来说是不合逻辑的。。。
		for(int i=0;i<50;i++){
			if(isPersonInfo){
				 this.info.setName("李兴华");
				 try{
					 Thread.sleep(90);  //故意出现延时,如果不把上下两个操作看成原子操作的话,就可能别别的线程篡改
				 }catch(Exception e){}
				 
				 this.info.setContent("java讲师");
				 isPersonInfo = false;
			}else{
				this.info.setName("mldn");
				try{
					 Thread.sleep(90);  //故意出现延时,如果不把上下两个操作看成原子操作的话,就可能别别的线程篡改
				 }catch(Exception e){}
				this.info.setContent("www.mldnjava.com");
				isPersonInfo = true;
			}
		}
	}
}

class Consumer implements Runnable{
		private Info info = null;
		public Consumer(Info info){
			this.info = info;
		}
		
		public void run(){
			for(int i=0;i<50;i++){ //消费者休息90秒就去取东西
				try{
					Thread.sleep(90);
				}catch(Exception e){
					
				}
				System.out.println(this.info.getName()+"--->"+this.info.getContent());
			}
		}
}

class ThreadCaseDemo01{
	public static void main(String args[]){
		Info info = new Info();
		Producer pro = new Producer(info);
		Consumer comsumer = new Consumer(info);
		new Thread(pro).start();
		new Thread(pro).start();
	}
}

//以上的程序很可能被篡改。。。

我们改变下代码,因为篡改是没有原子操作,所以我们给他来个原子操作,最好把需要原子化的这些操作放到一个方法里面,然后同步方法即可。

class Info{
	private String name = "李兴华";
	private String content = "Java讲师";
	
	public synchronized void set(String name,String content){
		this.name = name;
		 try{
			 Thread.sleep(90);  //故意出现延时,如果不把上下两个操作看成原子操作的话,就可能别别的线程篡改
		 }catch(Exception e){}
		this.content = content;
	}
	
	public synchronized void get(){
		System.out.println(this.name+"---->"+this.content);
	}
	

}

class Producer implements Runnable{
	private Info info = null;
	public Producer(Info info){
		this.info = info;
	}
	 
	public void run(){
		boolean isPersonInfo = false; //这个工厂生产两种东西,而且是交替生产
		for(int i=0;i<50;i++){
			if(isPersonInfo){
				 this.info.set("李兴华", "java讲师");
				 isPersonInfo = false;
			}else{
				this.info.set("mldn", "www.mldnjava.com");
				isPersonInfo = true;
			}
		}
	}
}

class Consumer implements Runnable{
		private Info info = null;
		public Consumer(Info info){
			this.info = info;
		}
		
		public void run(){
			for(int i=0;i<50;i++){ //消费者休息90秒就去取东西
				try{
					Thread.sleep(90);
				}catch(Exception e){
					
				}
				this.info.get();
			}
		}
}

//上面的代码使得操作原子化了,但是发生了重复取东西的情况,并没有达到设置一个取走一个的目的,要解决这个问题,需要使用等待与唤醒机制

在Object类中的唤醒有两个:notify() 和notifyAll()

一般来说,等待的线程一般会按照顺序排列,如果现在使用了notify()方法的话,则会唤醒第一个等待的线程执行,如果使用notifyAll()方法的话,则会唤醒所有等待的线程,那么优先级最高的那个线程就有可能先执行

因为set和get的时候需要判断是否有人在操作,那么我们可以修改info类

class Info{
	private String name = "李兴华";
	private String content = "Java讲师";
        // private boolean isProducing = true;//因为Info是临界区,当然他最清楚谁在里面
        //修改得更加易于阅读
        private boolean producerHaveLock = true;
    	
         //因为是放东西到仓库里面,当然是生产者的行为
  //synchronized是为了防止多个同类线程进入
 //但是他不能防止set和get操作在同一时间只能发生一个,为了使得两个毫不相关的方法也同步起来,那么只能使用一个变量来判断是否有线程在执行,并且启用wait()和notify()来同步多个方法。。。哈哈。。终于找到精髓
	public synchronized void set(String name,String content){
               //如果消费者在里面我就等。。。
                 if(!lockInProducer()){                     
                     try{super.wait(); }catch(Exception e){}
                 }
             //----等待通过,这个时候也就是说消费者出来了后,我进行生产
		this.name = name;
		 try{
			 Thread.sleep(90);  //故意出现延时,如果不把上下两个操作看成原子操作的话,就可能别别的线程篡改
		 }catch(Exception e){}
		this.content = content;
             //生产完成
                 giveLock2Coustomer();       
           }
	
	public synchronized void get(){
                 if(lockInProducer()){
                     super.wait();
                 }

                 try{
                   Thread.sleep(300);
                 }catch(Exception e){}
              	System.out.println(this.name+"---->"+this.content);
                 giveLock2Produce();
         }
	
         private void giveLock2Produce(){
               producerHaveLock = true;
               super.notify();
         }
         private void giveLock2Coustomer(){
               producerHaveLock = false;
               super.notify();
         }
         private boolean lockInProducer(){
              return producerHaveLock ;
         }

}



还有几个方法已经不建议使用了,因为很可能引起死锁问题。。。
suspend();挂起  resume()反挂起
stop()定制线程

如果我们现在要想停止一个线程运行怎么办。。。?

用设置标志位的方法啦。。
class MyThread implements Runnable{
   private boolean isStop = true;
  public void run(){
     int i = 0;
      while(!isStop){
         System.out.println("运行了"+i+“次”);
      }
  }

   public void stop(){
       this.isStop = false;
   }
}

public class Test{
   public static void main(String[] args){
       MyThread m = new MyThread();
       Thread t = new Thread(m);
       t.start();
        Thread.sleep(500);
        m.stop();
   }
}
---------------------------------------------------------------------------
sleep和wait的区别
sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep方法并不会释放锁,即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行。wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。

public class MultiThread {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new Thread(new Thread1()).start();
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		new Thread(new Thread2()).start();
	}

	private static class Thread1 implements Runnable {
	    
		public void run() {
			synchronized (MultiThread.class) {
				System.out.println("enter thread1...");
				System.out.println("thread1 is waiting");
				try {
					// 释放锁有两种方式,第一种方式是程序自然离开监视器的范围,也就是离开了synchronized关键字管辖的代码范围,另一种方式就是在synchronized关键字管辖的代码内部调用监视器对象的wait方法。这里,使用wait方法释放锁。
					MultiThread.class.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println("thread1 is going on...");
				System.out.println("thread1 is being over!");
			}
		}
	}

	private static class Thread2 implements Runnable {

		public void run() {
			// TODO Auto-generated method stub
			synchronized (MultiThread.class) {

				System.out.println("enter thread2...");
				System.out.println("thread2 notify other thread can release wait status..");
				// 由于notify方法并不释放锁,
				// 即使thread2调用下面的sleep方法休息了10毫秒,但thread1仍然不会执行,因为thread2没有释放锁,所以Thread1无法得到锁。
				MultiThread.class.notify();

				System.out.println("thread2 is sleeping ten millisecond...");
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println("thread2 is going on...");
				System.out.println("thread2 is being over!");
			}
		}
	}
}



你可能感兴趣的:(thread,J2SE)