zoukankan      html  css  js  c++  java
  • 黑马程序员————java线程之间的通信

    ------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
    

      多线程可以让我们同时共享一个资源,但如果在共享这个资源时需要彼此之间的联系怎么做呢?

    经典实例:生产者与消费者。

    问题描述,生产者每生产一个消费者就要取走一个,同时进行。

    首先java为我们提供了一套等待唤醒机制,让线程与线程之间产生了联系。线程是分五个状态的:创建;运行;阻塞;冻结;消亡。java提供了几个针对状态的方法

    wait()方法让线程进入冻结状态,让出cpu,让出锁;

    notify()方法唤醒进入冻结状态的线程,notifyAll()是唤醒所有的线程。

    针对问题,我们可以对生产者设定一个开关,如果资源为0就允许其生产并在生产完之后将开关关上,不会在有生产者生产并唤醒其他线程也就是消费者线程,当然在这之上同样要用到同步,为了保证第一个生产者进去之时,其他生产者会被拒之门外,对于消费者同理。

    public static void main(String[] args) {
    		// 
    		tongbu i=new tongbu();//创建抽取出来的同步方法对象
    		hjw j=new hjw(i);//创建实现Runnable接口的对象
    		bb k=new bb(i);
    		Thread xc1 =new Thread(j);//创建线程
    		Thread xc2 =new Thread(k);
    		xc1.setName("生产者");
    		xc2.setName("消费者");
    		xc1.start();
    		xc2.start();
    	}
    
    }
    class tongbu{//将两个同步方法抽取出来
    	private String name;
    	private int count=1;
    	boolean flag=false;//定义一个bool类型来作用等待唤醒机制
    	public synchronized void set(String name){//生产者的同步函数
    		if(flag){//已存在就睡眠
    			try{
    				wait();
    			}
    				
    			catch(Exception e){}
    			}
    		//否则 运作代码
    		this.name=name+"---"+count++;
    		System.out.println(Thread.currentThread().getName()+this.name);
    		flag=true;//改变bool值
    		this.notify();//唤醒线程
    	}
    
    	public synchronized void get(){
    		if(!flag){//进入休眠
    			try{
    				wait();
    			}
    				
    			catch(Exception e){}
    			}
    		//被生产者唤醒
    		System.out.println(Thread.currentThread().getName()+"---"+this.name);
    		flag=false;
    		this.notify();//唤醒线程
    	}
    }
    class hjw implements Runnable{
    	private tongbu x ;
    	hjw(tongbu x){//传回tongbu对象
    		this.x=x;
    	}
    	public void run(){//重写run方法
    		
    		while(true){
    		x.set("饼干");
    		}
    	}
    }
    class bb implements Runnable{
    	private tongbu x ;
    	bb(tongbu x){//传回tongbu对象
    		this.x=x;
    	}
    	public void run(){//重写run方法
    		
    		while(true){
    		x.get();
    		}
    	}
    }
    	
    

      这只是对于生产者和消费者只有一个线程,如果这边都有多个线程呢?绝不是多创建几个线程那么简单,因为要notify方法是唤醒最先休眠的那个线程,也就是说转到后面会出,生产一个,消费两次,生产多个只消费其中一个。

    那么如何避免呢?采用while循环替代if循环,每当线程解冻之后,重新开始循环而非接着向下执行,这样就避免了多次执行,但问题是依据notify()的特性还是会让所有线程都陷入等待,我需要唤醒对方线程,所有这个时候就要用到notifyAll()了,唤醒所有线程。

    public static void main(String[] args) {
    		// 
    		tongbu i=new tongbu();//创建抽取出来的同步方法对象
    		hjw j=new hjw(i);//创建实现Runnable接口的对象
    		bb k=new bb(i);
    		Thread xc1 =new Thread(j);//创建线程
    		Thread xc2 =new Thread(k);
    		xc1.setName("生产者");
    		xc2.setName("消费者");
    		xc1.start();
    		xc2.start();
    	}
    
    }
    class tongbu{//将两个同步方法抽取出来
    	private String name;
    	private int count=1;
    	boolean flag=false;//定义一个bool类型来作用等待唤醒机制
    	public synchronized void set(String name){//生产者的同步函数
    		while(flag){//已存在就睡眠
    			try{
    				wait();
    			}
    				
    			catch(Exception e){}
    			}
    		//否则 运作代码
    		this.name=name+"---"+count++;
    		System.out.println(Thread.currentThread().getName()+this.name);
    		flag=true;//改变bool值
    		this.notifyAll();//唤醒线程
    	}
    
    	public synchronized void get(){
    		while(!flag){//进入休眠
    			try{
    				wait();
    			}
    				
    			catch(Exception e){}
    			}
    		//被生产者唤醒
    		System.out.println(Thread.currentThread().getName()+"---"+this.name);
    		flag=false;
    		this.notifyAll();//唤醒线程
    	}
    }
    class hjw implements Runnable{
    	private tongbu x ;
    	hjw(tongbu x){//传回tongbu对象
    		this.x=x;
    	}
    	public void run(){//重写run方法
    		
    		while(true){
    		x.set("饼干");
    		}
    	}
    }
    class bb implements Runnable{
    	private tongbu x ;
    	bb(tongbu x){//传回tongbu对象
    		this.x=x;
    	}
    	public void run(){//重写run方法
    		
    		while(true){
    		x.get();
    		}
    	}
    }
    

      事实上,java5.0版本提供更完善的解决方案,针对如何唤醒指定线程。在java.lang.util.concurrent.locks中,提供了方法将锁显示化用以取代同步synchronized,lock()开锁,unlock()关锁,关锁这一特点犹如关闭资源就是无论怎样都要执行,因为前面有异常需要处理,所以关锁这一操作放在了finally{}中;而对于Object中wait()方法和notify(),notifyAll()方法分别用condition的await(),signal()和signalAll()取代,在lock中有一个new condition的方法,所以可以通过创建多个condition类,实现对指定线程的操作。

  • 相关阅读:
    信息安全系统设计基础第九周学习总结
    信息安全程序设计基础第五周学习总结
    信息安全程序设计基础第二周学习总结
    信息安全程序设计基础第三周总结
    ubuntu 13.10安装jdk 1.7 owen
    vim的配置文件 owen
    程序的思想是相通的,语言只是一种手段 owen
    如何删除开机系统选择 owen
    easybcd添加或删除启动选项 owen
    星际译王词库 owen
  • 原文地址:https://www.cnblogs.com/huangjiawei/p/4706314.html
Copyright © 2011-2022 走看看