黑马程序员_多线程(二)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

七、线程间通信

线程间通信概念:多线程在操作同一资源但是操作动作不一样。


等待唤醒机制涉及的方法:

wait:将同步中的线程处于冻结状态。释放了执行权和资格。同时将线程对象储存到了线程池中。

notify:唤醒线程池中某一个等待线程。

notifyAll:唤醒线程池中所有线程。

注意:

这些方法必须定义在同步中,因为这些方法是操作线程的方法。

这些方法必须要标识所属的锁。

为什么要定义notifyAll?

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


为什么操作线程的方法wait、notify、notifyAll定义在了Object类中?

因为这些方法是监视器的方法,监视器其实就是锁。锁可以是任意对象,那么能被任意对象调用的方法一定定义在Object中


wait和sleep的区别

wait:可以指定时间也可以不指定时间。不指定时间,只能由对应的notify或者notifyAll来唤醒。

sleep:必须指定时间。

wait:线程会释放执行权,而且线程会释放锁。

sleep:线程会释放执行权,但是不会释放锁。

//生产者和消费者问题,一个线程存入姓名和性别,另一个线程打印存入的姓名和性别
class Resource 
//定义一个用于存储和取出的资源
{
	private String name;
	private String sex;
	private booean flag=false;
<span style="white-space:pre">	</span>//等待唤醒机制
	public synchronized void set(String name,String sex)
	{
		if(flag)
			try
			{
				this.wait();//等待
			}
			catch (InterruptedException e)
			{
			}
		this.name = name
		this.sex = sex
		flag = true;
		this.notify();//唤醒
	}

	public synchronized void out()
	{
		if(!flag)
			try
			{
				this.wait();//等待
			}
			catch (InterruptedException e)
			{
			}
		System.out.println(name+"....."+sex);
		flag = false;
		this.notify();//唤醒
	}
}
//输入线程
class Input implements Runnable
{
	private Rseource r;

	Input(Resource)
	{
		this.r = r;
	}

	public void run()//复写run方法
	{
		int x = 0;
		while(true)
		{
			if(x == 0)
			{
			r.set("mike","男");
			}
			else
		    {
				r.set("lili","女");
			}
			x=(x+1)%2;//依次输入男女
		}
	}
}


//输出线程
class Output implements Runnable
{
	private Resource r;

	Output(Respurce r)
	{
		this.r = r;
	}
	public void run()//复写run方法
	{
		while(true)
		{
			r.out();
		}
	
	}
}

class  
{
	public static void main(String[] args) 
	{
		Resource r = new Resource();//将类实例化

		new Thread(new Input(r)).start();//创建并开启线程
		new Thread(new Output(r)).start();
	}
}


八、生产者和消费者JDK1.5升级解决方案

将同步synchronized替换成显示的Lock操作。将ObjectwaitnotifynotifyAll,替换成了Condition对象。该Condition对象可以通过Lock锁进行获取,并支持多个相关的Condition对象。

Condition接口中的await方法对应于Object中的wait方法。
Condition接口中的signal方法对应于Object中的notify方法。
Condition接口中的signalAll方法对应于Object中的notifyAll方法。

利用JDK1.5新特性完善多生产者和多消费者问题代码如下:

import java.util.concurrent.locks.*;
class Resource{
	private String name ;
	private int count = 1;
	private boolean flag = false;
      
	Lock lock = new ReentrantLock();//创建一个锁对象
         
	Condition con = lock .newCondition(); //通过已有的锁获取该锁上的监视器对象   

	//通过已有的锁获取两组监视器,分别用来控制生产者和消费者的等待唤醒机制。
	Condition producer_con = lock .newCondition();
	Condition consumer_con = lock .newCondition();

	public void set(String name)
		{
			lock.lock();
			try{
				while(flag )//重复判断标识,确认是否生产  
					try
					{
					  producer_con.await();
					} 
					catch(InterruptedException e){}
				   this.name = name + count;
				   count++;
				   System.out.println(Thread.currentThread().getName() + "...生产者..." + this. name);
				   flag = true ;//控制生产/消费标识
				   consumer_con.signalAll();
				} 
			finally
			{
				lock.unlock();//一定要关闭资源所以使用finally方法解锁
			}
		}

       public void out()
		   {
             lock.lock();
             try{
                   while(!flag )//重复判断标识,确认是否消费
                         try
                         {
                               consumer_con.await();
                         } 
						catch(InterruptedException e){}
                   flag = false ;//控制生产/消费标识
                   producer_con.signal();
                   System.out.println(Thread.currentThread().getName() + "...消费者..." + this. name);
				} 
			finally
			{
				lock.unlock();//一定要关闭资源所以使用finally方法解锁
            }
      }
}
//生产者线程
class Producer implements Runnable{
       private Resource r ;
       Producer(Resource r){
             this.r = r;
       }
       public void run(){           //复写run方法
             while(true ){
                   r.set("商品");
            }
      }
 }
//消费者线程
class Consumer implements Runnable{
       private Resource r ;
       Consumer(Resource r){
             this.r = r;
       }
       public void run(){           //复写run方法
             while(true ){
                   r.out();
            }
      }
}

class ProducerConsumerDemo {
       public static void main(String[] args){
            //将类实例化
			Resource r = new Resource();
            Producer pro = new Producer(r);
            Consumer con = new Consumer(r);
			//创建多线程
            Thread t0 = new Thread(pro);
            Thread t1 = new Thread(pro);
            Thread t2 = new Thread(con);
            Thread t3 = new Thread(con);
			//启动线程
            t0.start();
            t1.start();
            t2.start();
            t3.start();
      }
}

九、停止线程

stop方法已经过时

任务中都会有循环结构,只要控制住循环就可以结束任务。控制循环通常就用定义标记来完成。

在while循环中通常要判断标志flag。代码如下

public  void run()  
{  
    while(flag)  
    {     
        System.out.println(Thread.currentThread().getName()+"....run");  
    }  
}  

如果线程处于冻结状态无法读取flag如何结束?

可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备CPU的执行资格。

强制动作会发生InterruptedException,一定要记得处理。


十、线程的其他方法

守护线程

使用setDaemon方法将线程设置为守护线程,该方法必须在启动线程前调用。


join方法

临时加入一个线程的时候可以使用join方法

当A线程执行到B线程的join方式。A线程处于冻结状态,释放了执行权,B开始执行。只有当B线程运行结束后A才会从冻结状态恢复到运行状态执行。


yield方法

暂停当前正在执行的线程对象并执行其他线程


setPriority()方法用来设置优先级

MAX_PRIORITY 最高优先级10

        MIN_PRIORITY   最低优先级1

        NORM_PRIORITY 分配给线程的默认优先级





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值