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

------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 分配给线程的默认优先级





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
黑马程序员多线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印log之前能够同时开始等待1秒钟。一种解决思路是在线程的run方法中调用parseLog方法,并使用Thread.sleep方法让线程等待1秒钟。另一种解决思路是使用线程池,将线程数量固定为4个,并将每个调用parseLog方法的语句封装为一个Runnable对象,然后提交到线程池中。这样可以实现一秒钟打印4行日志,4秒钟打印16条日志的需求。 第个问题是如何修改代码,使得几个线程调用TestDo.doSome(key, value)方法时,如果传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果。一种解决方法是使用synchronized关键字来实现线程的互斥排队输出。通过给TestDo.doSome方法添加synchronized关键字,可以确保同一时间只有一个线程能够执行该方法,从而实现线程的互斥输出。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马程序员——多线程10:多线程相关练习](https://blog.csdn.net/axr1985lazy/article/details/48186039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值