zoukankan      html  css  js  c++  java
  • 黑马程序员——JAVA基础之多线程的线程间通讯等

    ------- android培训java培训期待与您交流! ----------

     

    线程间通讯:

    其实就是多个线程在操作同一个资源,但是动作不同。

    wait();

    在其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量前,导致当前线程等待。

    当前线程必须拥有此对象监视器。

    notify();

    唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。

    选择是任意性的,并在对实现做出决定时发生。

    线程通过调用其中一个 wait 方法,在对象的监视器上等待。 

    notifyAll(); 

    唤醒在此对象监视器上等待的所有线程。线程通过调用其中一个 wait 方法,在对象的监视器上等待。

     

    思考1:wait ( ),notify ( ),notifyAll ( ),用来操作线程为什么定义在了Object 类中?


         1,这些方法存在与同步中。
         2,使用这些方法时必须要标识所属的同步的锁。
         3,锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。

              因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。不可以对不同锁中的线程进行唤醒。 
     也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。


    思考2:wait ( ) ,sleep ( ) 有什么区别?


         wait ( ) : 释放cpu执行权,释放锁。
         sleep ( ) : 释放cpu执行权,不释放锁。

      

    /**
     * 
     * 多线程通讯示例:
     * 	多线程通讯就是多个线程共同操作同一个资源,但是动作不同
     * 例:开启两个线程,交替输入输出两个人的名字和年龄
     *
     */
    public class ThreadTest 
    {
    	public static void main(String[] args)
    	{
    		Person p = new Person();
    		Input in = new Input(p);
    		Output out = new Output(p);
    		
    		Thread t1 = new Thread(in);
    		Thread t2 = new Thread(out);
    		
    		t1.start();
    		t2.start();
    	}
    }
    
    //声明一个Person类,有两个属性,姓名和性别
    class Person
    {
    	String name;
    	String sex;
    }
    
    //声明一个输入线程继承Runnable。传入名字和性别
    class Input implements Runnable
    {
    	private Person p;
    	
    	Input (Person p)
    	{
    		this.p = p;
    	}
    	
    	public void run()
    	{
    		int x = 0;
    		
    		while(true)
    		{
    			synchronized (p)
    			{
    				if (x==0)
    				{
    					p.name = "lilei";
    					p.sex = "boy";
    				}
    				else 
    				{
    					p.name = "hanmeimei";
    					p.sex = "girl";
    				}
    				x = (1+x)%2;
    			}
    		}
    	}
    }
    
    //声明一个输出线程的类继承Runnable,输出姓名和性别
    class Output implements Runnable
    {
    	private Person p;
    	
    	Output(Person p)
    	{
    		this.p = p;
    	}
    	
    	public void run()
    	{
    		while(true)
    		{
    			synchronized (p)
    			{
    				System.out.println("name: "+p.name+"-------sex: "+p.sex);
    			}
    		}
    	}
    }
    


     

    等待唤醒机制:

     

    改进一下这个程序,让输入输出交替进行


     

    /**
     * 
     * 多线程通讯示例:
     * 	多线程通讯就是多个线程共同操作同一个资源,但是动作不同
     * 例:开启两个线程,交替输入输出两个人的名字和年龄
     *
     */
    public class ThreadTest 
    {
    	public static void main(String[] args)
    	{
    		Person p = new Person();
    		Input in = new Input(p);
    		Output out = new Output(p);
    		
    		Thread t1 = new Thread(in);
    		Thread t2 = new Thread(out);
    		
    		t1.start();
    		t2.start();
    	}
    }
    
    //声明一个Person类,有两个属性,姓名和性别
    class Person
    {
    	String name;
    	String sex;
    	boolean flat;
    }
    
    //声明一个输入线程继承Runnable。传入名字和性别
    class Input implements Runnable
    {
    	private Person p;
    	
    	Input (Person p)
    	{
    		this.p = p;
    	}
    	
    	public void run()
    	{
    		int x = 0;
    		
    		while(true)
    		{
    			synchronized (p)
    			{
    				if (p.flat)
    					try{p.wait();}catch(Exception e){}
    				if (x==0)
    				{
    					p.name = "lilei";
    					p.sex = "boy";
    				}
    				else 
    				{
    					p.name = "hanmeimei";
    					p.sex = "girl";
    				}
    				x = (1+x)%2;
    				p.flat = true;
    				p.notify();
    			}
    		}
    	}
    }
    
    //声明一个输出线程的类继承Runnable,输出姓名和性别
    class Output implements Runnable
    {
    	private Person p;
    	
    	Output(Person p)
    	{
    		this.p = p;
    	}
    	
    	public void run()
    	{
    		while(true)
    		{
    			synchronized (p)
    			{
    				if (!p.flat)
    					try{p.wait();}catch(Exception e){}
    				System.out.println("name: "+p.name+"-------sex: "+p.sex);
    				p.flat = false;
    				p.notify();
    			}
    		}
    	}
    }
    


     

    发现有些数据不能被外界直接调用,具有安全隐患,所以改进如下:

    /**
     * 
     * 多线程通讯示例:
     * 	多线程通讯就是多个线程共同操作同一个资源,但是动作不同
     * 例:开启两个线程,交替输入输出两个人的名字和年龄
     *
     */
    public class ThreadTest 
    {
    	public static void main(String[] args)
    	{
    		Person p = new Person();
    		Input in = new Input(p);
    		Output out = new Output(p);
    		
    		Thread t1 = new Thread(in);
    		Thread t2 = new Thread(out);
    		
    		t1.start();
    		t2.start();
    	}
    }
    
    //声明一个Person类,有两个属性,姓名和性别
    class Person
    {
    	//私有数据,更安全
    	private String name;
    	private String sex;
    	private boolean flat;
    	
    	public synchronized void set(String name,String sex)
    	{
    		if (flat)
    			try{this.wait();}catch(Exception e){}
    		this.name = name;
    		this.sex = sex;
    		flat = true;
    		this.notify();	
    	}
    	
    	public synchronized void out()
    	{
    		if (!flat)
    			try{this.wait();}catch(Exception e){}
    		System.out.println("name: "+name+"-------sex: "+sex);
    		flat = false;
    		this.notify();
    	}
    }
    
    //声明一个输入线程继承Runnable。传入名字和性别
    class Input implements Runnable
    {
    	private Person p;
    	
    	Input (Person p)
    	{
    		this.p = p;
    	}
    	
    	public void run()
    	{
    		int x = 0;
    		
    		while(true)
    		{
    			if (x==0)
    				p.set("lilei","boy");
    			else
    				p.set("hanmeimei","girl");
    			x = (x+1)%2;			
    		}
    	}
    }
    
    //声明一个输出线程的类继承Runnable,输出姓名和性别
    class Output implements Runnable
    {
    	private Person p;
    	
    	Output(Person p)
    	{
    		this.p = p;
    	}
    	
    	public void run()
    	{
    		while(true)
    		{
    			p.out();
    		}
    	}
    }
    



    为什么定义notifyAll:

     

    因为需要唤醒对方线程。
    因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。

     

    /**
     * 
     * 当出现两个以上多线程进行多线程通讯的时候,需要用的notifyAll();
     * 例子:
     * 		生产者消费者
     *
     */
    public class ProCusDemo 
    {
    	public static void main(String[] args)
    	{
    		Resource r = new Resource();
    		
    		Pro p = new Pro(r);
    		Cus c = new Cus(r);
    		
    		Thread t1 = new Thread(p);
    		Thread t2 = new Thread(p);
    		Thread t3 = new Thread(c);
    		Thread t4 = new Thread(c);
    		
    		t1.start();
    		t2.start();
    		t3.start();
    		t4.start();
    	}
    }
    
    //声明一个资源类,赋予基本属性
    class Resource
    {
    	private String name;
    	private int count = 1;
    	private boolean flat;
    	
    	public synchronized void set(String name)
    	{
    		while (flat)//用while让被唤醒的线程再一次判断标记
    			try{wait();}catch(Exception e){}
    		this.name = name+"-----"+count++;
    		
    		System.out.println(Thread.currentThread().getName()+"---生产者---"+this.name);
    		flat = true;
    		notifyAll();
    	}
    	
    	public synchronized void out()
    	{
    		while (!flat)//用while让被唤醒的线程再一次判断标记
    			try{wait();}catch(Exception e){}
    		
    		System.out.println(Thread.currentThread().getName()+"---消费者---"+this.name);
    		flat = false;
    		notifyAll();
    	}
    }
    
    class Pro implements Runnable
    {
    	private Resource r;
    	
    	Pro(Resource r)
    	{
    		this.r = r;
    	}
    	
    	public void run()
    	{
    		while (true)
    		{
    			r.set("商品");
    		}
    	}
    }
    
    class Cus implements Runnable
    {
    	private Resource r;
    	
    	Cus(Resource r)
    	{
    		this.r = r;
    	}
    	
    	public void run()
    	{
    		while (true)
    		{
    			r.out();
    		}
    	}
    }
    


     JDK1.5 中提供了多线程升级解决方案。

    将同步Synchronized替换成现实Lock操作。

    将Object中的wait,notify notifyAll,替换了Condition对象。 

    该对象可以Lock锁进行获取。

    该示例中,实现了本方只唤醒对方操作。
     
    Lock:替代了Synchronized 
        lock 
        unlock
        newCondition()
     
    Condition:替代了Object wait notify notifyAll
        await();
        signal();
        signalAll();

     

    <span style="font-size:14px;">import java.util.concurrent.locks.*;
    
    class ProducerConsumerDemo2 
    {
    	public static void main(String[] args) 
    	{
    		Resource r = new Resource();
    
    		Producer pro = new Producer(r);
    		Consumer con = new Consumer(r);
    
    		Thread t1 = new Thread(pro);
    		Thread t2 = new Thread(pro);
    		Thread t3 = new Thread(con);
    		Thread t4 = new Thread(con);
    
    		t1.start();
    		t2.start();
    		t3.start();
    		t4.start();
    
    	}
    }
    
    class Resource
    {
    	private String name;
    	private int count = 1;
    	private boolean flag = false;
    			
    	private Lock lock = new ReentrantLock();
    
    	private Condition condition_pro = lock.newCondition();
    	private Condition condition_con = lock.newCondition();
    
    
    
    	public  void set(String name)throws InterruptedException
    	{
    		lock.lock();
    		try
    		{
    			while(flag)
    				condition_pro.await();//t1,t2
    			this.name = name+"--"+count++;
    
    			System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
    			flag = true;
    			condition_con.signal();
    		}
    		finally
    		{
    			lock.unlock();//释放锁的动作一定要执行。
    		}
    	}
      
    	public  void out()throws InterruptedException
    	{
    		lock.lock();
    		try
    		{
    			while(!flag)
    				condition_con.await();
    			System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
    			flag = false;
    			condition_pro.signal();
    		}
    		finally
    		{
    			lock.unlock();
    		}		
    	}
    }
    
    class Producer implements Runnable
    {
    	private Resource res;
    
    	Producer(Resource res)
    	{
    		this.res = res;
    	}
    	public void run()
    	{
    		while(true)
    		{
    			try
    			{
    				res.set("+商品+");
    			}
    			catch (InterruptedException e)
    			{
    			}
    			
    		}
    	}
    }
    
    class Consumer implements Runnable
    {
    	private Resource res;
    
    	Consumer(Resource res)
    	{
    		this.res = res;
    	}
    	public void run()
    	{
    		while(true)
    		{
    			try
    			{
    				res.out();
    			}
    			catch (InterruptedException e)
    			{
    			}
    		}
    	}
    }
    </span>

     

    如何停止线程:


         1.  定义循环结束标记,因为线程运行代码一般都是循环,只要控制了循环即可。
         2.  注:stop方法已经过时不再使用。


    stop方法已经过时,如何停止线程?


           只有一种,run方法结束。开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。
           特殊情况:当线程处于了冻结状态。就不会读取到标记。那么线程就不会结束。


            当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。使用interrupt(中断)方法。
            该方法是结束线程的冻结状态,使线程回到运行状态中来。



     

    <span style="font-size:14px;">class StopThread implements Runnable
    {
    	private boolean flag =true;
    	public synchronized void run()
    	{
    		while(flag)
    		{
    			try
    			{
    				wait();
    			}
    			catch (InterruptedException e)
    			{
    				System.out.println(Thread.currentThread.getName()+".....Exception");
    				flag = false;
    			}
    			System.out.println(Thread.currentThread.getName()+".......run");
    		}
    	}
    	public void changeFlag()
    	{
    		flag = false;
    	}
    }
    
    class  StopThreadDemo
    {
    	public static void main(String[] args) 
    	{
    		StopThread st = new StopThread();
    		
    		Thread t1 = new Thread(st);
    		Thread t2 = new Thread(st);
    
    		t1.start();
    		t2.start();
    
    		int num = 0;
    
    		while(true)
    		{
    			if(num++ == 60)
    			{
    				//st.changeFlag();
    				t1.interrupt();
    				t2.interrupt();
    				break;
    			}
    			System.out.println(Thread.currentThread().getName()+"......."+num);
    		}
    		System.out.println("over");
    	}
    }
    </span>

     

    守护线程:

    前台线程执行完之后后台线程自动执行完,主线程是前台线程。

    <span style="font-size:14px;">class StopThread implements Runnable
    {
    	private boolean flag =true;
    	public synchronized void run()
    	{
    		while(flag)
    		{
    			try
    			{
    				wait();
    			}
    			catch (InterruptedException e)
    			{
    				System.out.println(Thread.currentThread.getName()+".....Exception");
    				flag = false;
    			}
    			System.out.println(Thread.currentThread.getName()+".......run");
    		}
    	}
    	public void changeFlag()
    	{
    		flag = false;
    	}
    }
    
    class  StopThreadDemo
    {
    	public static void main(String[] args) 
    	{
    		StopThread st = new StopThread();
    		
    		Thread t1 = new Thread(st);
    		Thread t2 = new Thread(st);
    
    		t1.setDaemon(true);
    		t2.setDaemon(true);
    		t1.start();
    		t2.start();
    
    		int num = 0;
    
    		while(true)
    		{
    			if(num++ == 60)
    			{
    				//st.changeFlag();
    				//t1.interrupt();
    				//t2.interrupt();
    				break;
    			}
    			System.out.println(Thread.currentThread().getName()+"......."+num);
    		}
    		System.out.println("over");
    	}
    }
    </span>

     

     

     

    join用法:

    当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。
     
    join可以用来临时加入线程执行。

    <span style="font-size:14px;">class Demo implements Runnable
    {
    	public void run()
    	{
    		for(int x=0; x<70; x++)
    		{
    			System.out.println(Thread.currentThread().getName()+"...."+x);
    		}
    	}
    }
    
    class  JoinDemo
    {
    	public static void main(String[] args) throws Exception
    	{
    		Demo d = new Demo();
    		Thread t1 = new Thread(d);
    		Thread t2 = new Thread(d);
    		t1.start();
    		t1.join();//此时t1线程获得执行权,主线程冻结。
    		t2.start();
    
    		for(int x=0; x<80; x++)
    		{
    			System.out.println("main....."+x);
    		}
    		System.out.println("over");
    	}
    }
    </span>

     

    yield() :

     

       可以稍微减缓程序运行,产生近似于交替运行的效果。

     

    class Demo implements Runnable
    {
    	public void run()
    	{
    		for(int x=0; x<70; x++)
    		{
    			System.out.println(Thread.currentThread().toString()+"....."+x);//toString()显示优先级,优先级1~10,默认5
    			Thread.yield();//让程序稍微暂停一下,释放执行权,产生交替运行的效果
    		}
    	}
    }
    
    class  JoinDemo
    {
    	public static void main(String[] args) throws Exception
    	{
    		Demo d = new Demo();
    		Thread t1 = new Thread(d);
    		Thread t2 = new Thread(d);
    		t1.start();
    		//t1.setPriority(Thread.MAX_PRIORITY); 设置最大优先级
    		t2.start();
    
    		for(int x=0; x<80; x++)
    		{
    			System.out.println("main....."+x);
    		}
    		System.out.println("over");
    	}
    }
    


     

    ------- android培训java培训、期待与您交流! ----------




  • 相关阅读:
    ASP.NET Web API 2.0 统一响应格式
    [翻译]ASP.NET Web API 2 中的全局错误处理
    【WPF】UserControl 的 Load事件
    解决MS SQL Server 使用HashBytes函数乱码问题
    实例化MD5CryptoServiceProvider报错:此实现不是 Windows 平台 FIPS 验证的加密算法的一部分
    添加扩展方法,提示编译错误 “缺少编译器要求的成员”
    [调试]VS2013调试时提示“运行时当前拒绝计算表达式的值”
    jquery chosen 插件多选初始化
    Asp.net WebForm 中无法引用App_Code文件夹下的类
    文本非法字符过滤 简体转换繁体
  • 原文地址:https://www.cnblogs.com/runwind/p/4212194.html
Copyright © 2011-2022 走看看