黑马程序员--- 学习笔记(第十二天

本文详细介绍了Java中多线程间的通信机制,包括通过共享资源实现的生产者-消费者模型,以及如何利用wait(), notify(), notifyAll()等方法进行线程间的同步控制。此外,还探讨了如何通过ReentrantLock和Condition更精确地控制线程唤醒。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 —————————— ASP.Net+Android+IOS开发.Net培训、期待与您交流!——————————
多线程之间的通信
其实就是多线程在操作同一资源,但是操作的动作不同


/*
多线程之间的通信

一个线程负责写,一个线程负责读


*/
class Demo 
{
	public static void main(String[] args) 
	{
		 Resource r=new Resource();
		 new Thread(new WriterThread(r)).start();
		 new Thread(new ReaderThread(r)).start();
	}
}
/*操作共同的资源*/
class Resource
{
   private String name;
   private String sex;
   private boolean flag=true;
   public void setFlag(boolean flag){
   		this.flag=flag;
   }
   public synchronized void setInfo(String name,String sex){
	   while(flag){ //每次都判断标记
			try
			{
				wait();
			}
			catch (InterruptedException e)
			{
			}
	   }
		this.name=name;
		this.sex=sex;
		flag=true;
		notifyAll();
   }
   public synchronized void getInfo(){
	    while(!flag){
			try
			{
				wait();
			}
			catch (InterruptedException e)
			{
			}
	   }
		System.out.println(name+"-----"+sex);
		flag=false;
		notifyAll();
   }

}
/*写入线程*/
class WriterThread implements Runnable
{
	private Resource r;
	public WriterThread(Resource r){
		this.r=r;			
	}
	public void run(){
		  int i=0;
		while(true){
			if(i%2==0){
				r.setInfo("track","man");
			}else{
				r.setInfo("赖海娟","女");
			}
			i++;
		}
	}

}
/*读取线程*/
class ReaderThread  implements Runnable
{
   private Resource r;
	public ReaderThread(Resource r){
		this.r=r;			
	}
	public void run(){
		while(true){
			r.getInfo();
		}
	}
}



wait();
notify();
notifyAll();
都使用在同步中,因为要对持有监视器的线程操作,所以都要使用在
同步中,因为只有同步才具有监视器


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


一对一生产者,消费者:


/*
生产者,消费者

*/
class Demo1 
{
	public static void main(String[] args) 
	{
		 Resource r=new Resource();
		 new Thread(new Producer(r)).start();
		  new Thread(new Consumer(r)).start();
	}
}
/*共同所操作的资源*/
class Resource
{
	private String ware;
	private int count=1;
	private boolean b=false;
	public  String getWare(){
		return ware;
	}
	public synchronized  void proWare(String ware){
		while(b)
		try
		{
			wait();
		}
		catch (InterruptedException e)
		{
		}
		this.ware=ware+":::"+count++;
		b=true;
		notifyAll();
	}
	public synchronized void conWare(){
		while(!b)
		try
		{
			wait();
		}
		catch (InterruptedException e)
		{
		}
		 System.out.println("消费--------------"+ware);
		 b=false;
		 notifyAll();
	}
}
/*生产者*/
class Producer implements Runnable
{
	private Resource r;
	public Producer(Resource r){
		this.r=r;
	}
	public void run(){
		while(true){
		r.proWare("商品");
		System.out.println("生产-----------"+r.getWare());
		}
	}
}
/*消费者*/
class Consumer implements Runnable
{	
	private Resource r;
	public Consumer(Resource r){
		this.r=r;
	}
	public void run(){
		while(true)
			r.conWare();
	}
}




对于多个生产者和消费者
为什么要定义while判断标记?
原因:让被唤醒的线程再一次判断标记


/*
生产者 消费者 

使用JDK1.5提供的解决方案

只唤醒对方的等待线程
*/
import java.util.concurrent.locks.*;
class Demo2 
{
	public static void main(String[] args) 
	{
		 Resource r=new Resource();

		 /*两个生产者*/
		 new Thread(new Producer(r)).start();
		 new Thread(new Producer(r)).start();

		    /*两个消费者*/
		  new Thread(new Consumer(r)).start();
		  new Thread(new Consumer(r)).start();
	}
}
/*共同所操作的资源*/
class Resource
{
	private String ware;
	private int count=1;
	private boolean b=false;
	 private Lock lock=new ReentrantLock();
	 private Condition con_pro=lock.newCondition();
	 private Condition con_con=lock.newCondition();
	public  String getWare(){
		return ware;
	}
	public  void proWare(String ware)throws InterruptedException{
		lock.lock(); //	获取锁

		while(b)
			try
			{
				con_pro.await(); //等待
			}
			finally
			{
				lock.unlock();//释放锁
			}
		this.ware=ware+":::"+count++;
		b=true;	
		con_con.signalAll();//唤醒对方的等待线程
	}
	public  void conWare()throws InterruptedException{
		lock.lock();
		while(!b)
		try
		{
			con_con.await();
		}
		finally
		{
			lock.unlock();
		}
		 System.out.println(Thread.currentThread().getName()+"消费--------------"+ware);
		 b=false;
		 con_pro.signalAll();
	}
}
/*生产者*/
class Producer implements Runnable
{
	private Resource r;
	public Producer(Resource r){
		this.r=r;
	}
	public void run(){
		while(true){
			try
			{
				r.proWare("商品");
				System.out.println(Thread.currentThread().getName()+"生产-----------"+r.getWare());
			}
			catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
	}
}
/*消费者*/
class Consumer implements Runnable
{	
	private Resource r;
	public Consumer(Resource r){
		this.r=r;
	}
	public void run(){
		while(true){
				try{
					
					r.conWare();

				}
				catch (InterruptedException e)
				{
					e.printStackTrace();
				}
		}
	}
}



为什么定义notifyAll?
因为需要唤醒的对方线程.因为只用notify,容易出现只唤醒本方线程的
情况,导致程序中的所有程序都在等待.


如何只唤醒对方呢?
需要导包:java.util.concurrent.locks;
JDK1.5中提供了多线程升级解决方法.将同步synchronized替换成显示的Lock
操作. 将Object中的wait,notify,notifyAll替换成Condition对象,该对象
可以通过Lock锁进行获取?
 Lock lock=new ReentrantLock();
 Condition con=lock.newCondition();


在该示例中实现本方只唤醒对方操作?




停止线程
stop方法已经过时?
如何停止线程?只有一种方法就是run方法结束


/*
如何停止线程  清除线程的冻结状态interrupt
*/
class Demo3 
{
	public static void main(String[] args) 
	{
		Test t=new Test();
		Thread tt=new Thread(t);
		tt.start();
		try
		{
			Thread.sleep(5000);
			tt.interrupt();	//5秒清除线程的冻结状态,重新开始执行
		}
		catch (Exception e)
		{
		}
	}
}
class Test implements Runnable
{
	public synchronized void run(){
		for (int i=0;i<100 ;i++ )
		{
			System.out.println(Thread.currentThread().getName()+"::"+i);
			//假如出现wait,则线程冻结  需要清除该状态才可以继续执行
			if(i==10)
				try
				{
					wait();
				}
				catch (InterruptedException  e)
				{
					e.printStackTrace();
				}
		}
	}
	
}



开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以 
让run方法结束.也就是线程结束


特殊情况,当线程处于冻结状态,就不会读到标记,那么线程就不会结束


当没有指定的方式让冻结的线程恢复到运行状态,这时需要对冻结进行清除
,强制性制止过程恢复到运行状态中来,这样就可以操作标记让线程结束


Thread类提供了该方法 interrupt();


守护线程:
setDaemon();
将该线程标志为守护线程,或用户线程就是后台线程
必须在启动线程前调用,主线程运行完毕,守护线程机会结束.jvm虚拟机结束


join();
当A线程执行到了B线程的join方法时,就会等待,等b线程执行完毕.
A才会执行


join可以用来临时加入线程执行


toString();
返回线程名称,线程优先级,线程组


ThreadGroup 线程组几乎用不上,就是谁调用该线程,它就属于哪个组,开发不常见


setPriority();//默认优先级是5


MAX_PRIORITY; //最高优先级10
MIN_PRIORITY; //最低优先级1
NORM_PRIORITY;//默认优先级5


yield(); //暂停当前运行线程


当某些代码需要被同时执行时,就等着成线程对象.

开发通常使用Thread的匿名子类或者Runnable的匿名子类


/*
setDaemon守护线程 
join临时加入线程  
toString//返回线程名称,优先级,线程组
setPriority//设置优先级
yield//暂停线程运行
*/
class Demo4 
{
	public static void main(String[] args) 
	{
		
		Thread t1=new Thread(){
			public void run(){
				for (int i=1;i<=20 ;i++ )
				{
					System.out.println(Thread.currentThread().toString()+":::"+i);
					/*
					//当设置为守护线程时,即使wait 主线程运行完 主线程就会结束
					if(i==10){
						try
						{
							wait();
						}
						catch (InterruptedException e)
						{
						}
					}
					*/
				}
			}
		};


		Runnable r=new Runnable(){
			public void run(){
				for (int i=1;i<=20 ;i++ )
				{
					System.out.println(Thread.currentThread().toString()+":::"+i);
					/*
					//当设置为守护线程时,即使wait 主线程运行完 主线程就会结束
					if(i==10){
						try
						{
							wait();
						}
						catch (InterruptedException e)
						{
						}
					}
					*/
				}
			}
		};
		Thread t2=new Thread(r);
		//t1.setPriority(Thread.MAX_PRIORITY);//设置t1的优先级为10 最大
	
		//t1.setDaemon(true); //设置为守护线程
		//t2.setDaemon(true);
		t1.start();
		t2.start();
		
		t1.yield();	//暂停对当前运行线程 本人经测试 看不出啥  是不是单核电脑的忧桑?
		//主线程
	
		for (int i=1;i<=50 ;i++ )
				{
					System.out.println(Thread.currentThread().toString()+":::"+i);
				}
	

	   /*
	   //join();//用来临时加入线程
	   try
	   {
				t1.join();// 本人经测试 看不出啥  是不是单核电脑的忧桑?
	   }
	   catch (Exception e)
	   {
	   }
	   */
	}
}


 —————————— ASP.Net+Android+IOS开发.Net培训、期待与您交流!——————————

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值