学习多线程基础,这一篇就够啦!(二)

目录

第四部分:线程之间的通信

等待唤醒机制

例子:多生产者多消费者问题

优化: 新特性Lock,Condition

wait 和 sleep 区别?

停止线程

守护线程


学习多线程基础,这一篇就够啦!(一):https://blog.csdn.net/weixin_43827227/article/details/96606212

第四部分:线程之间的通信

概念:多个线程在处理同一资源,但是任务却不同。(同一个银行,有人存钱,有人取钱)

 

等待唤醒机制

涉及的方法:

1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。

2,notify():唤醒线程池中一个线程(任意).

3,notifyAll():唤醒线程池中的所有线程。

 

为什么这些方法都必须定义在同步中?

因为这些方法是用于操作线程状态的方法。必须要明确到底操作的是哪个锁上的线程。

 

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

因为这些方法是监视器的方法。监视器其实就是锁:Synchronized(对象即锁)。

锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中。

 

过程:

例子:

//用等待唤醒注意点: 1, 同步函数             2,wait和notify成对
//wait,notify,notifyAll这些方法都必须定义在同步中
	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();
	}

例子:多生产者多消费者问题

if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。

while判断标记,解决了线程获取执行权后,是否要运行!

 

notify:只能唤醒一个线程,如果本方唤醒了本方(多个set时),没有意义。而且while判断标记+notify会导致死锁(醒来进行while判断时,再次wait了,所有线程都wait,则死锁)。

 

notifyAll解决了本方线程一定会唤醒对方线程的问题。

(但此方法既唤醒对方,又唤醒本方,在进行while判断,降低了效率。JDK1.5对此进行了优化)

目前结论:多生产多消费时,用while 和 notifyAll进行判断与唤醒

弊端:既唤醒对方,又唤醒本方,在进行while判断,降低了效率

class Resource2 {
	private String nameString="烤鸭";
	private int count =1;
	private boolean flag =false;
//	Lock lock=new ReentrantLock();
//	Condition condition =lock.newCondition();
	
	public synchronized void set(String name) {
		while(flag)     
			//if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。
			//while判断标记,解决了线程获取执行权后,是否要运行!
			//notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。
			
			//结论:多生产多消费时,用while 和 notifyAll进行判断与唤醒
			//弊端:既唤醒对方,又唤醒本方,在进行while判断,降低了效率
			try {
				this.wait();
			} catch ( InterruptedException e) {
			}
		count=count+1;
		System.out.println(Thread.currentThread().getName()+"。。。。。生产者。。。。。"+this.nameString+count);
		flag=true;
		notifyAll();  //notifyAll解决了本方线程一定会唤醒对方线程的问题。
	}
	
	public synchronized void out() {//与上面的格式进行对比
//		lock.lock();
		try {
			while(!flag)
				try {
					this.wait();
				} catch ( InterruptedException e) {
				}
			System.out.println(Thread.currentThread().getName()+"。。。。。。。。消费者。。。。。。"+this.nameString+count);
			flag=false;
			notifyAll();
		} finally {
//			lock.unlock();
		}
	}
}

class Producer2 implements Runnable{
	private Resource2 r;   //传递参数      创建资源对象,然后传递给set out
	Producer2(Resource2 r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.set("烤鸭");
		}
	}
}

class Consumer implements Runnable
{
	private Resource2 r;    //传递参数      创建资源对象,然后传递给set out 
	Consumer(Resource2 r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.out();
		}
	}
}


public class ProducerConsumerDemo {
	public static void main(String[] args) {
		Resource2 resource2 =new Resource2();
		
		Producer2 producer2=new Producer2(resource2);
		Consumer consumer=new Consumer(resource2);
		
		Thread t1=new Thread(producer2);
		Thread t2=new Thread(producer2);
		Thread t3=new Thread(consumer);
		Thread t4=new Thread(consumer);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}

---------------------------------------------------------------------------------------------------------------------------------------------

优化: 新特性Lock,Condition

Lock替代synchronized

Condition替代那些监视器方法(object里的wait,notify和notifyAll)

---------------------------------------------------------------------------------------------------------------------------------------------

区别:以前的同步代码块和同步函数仅仅是封装体,自带锁(对锁的操作:获取、释放是隐式的,看不见)。

           而现在将锁封装变成了一个对象Lock:提供了lock() 和unlock() 即获取锁和释放锁的两个方法

          可以和任意锁进行组合

 

------------------------------------------------------------------------------

-------------------------------------------------------------------------------

https://img-blog.csdnimg.cn/2019072312442060.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzgyNzIyNw==,size_16,color_FFFFFF,t_70 ​​

 

Lock lock=new ReentrantLock();
Condition condition =lock.newCondition();

public synchronized void out() {
		while(!flag)
			try {
				//this.wait();
                        condition.await  ();
			} catch ( InterruptedException e) {
			}
		this.nameString =nameString+count;
		System.out.println(Thread.currentThread().getName()+"。消费者。。。。。。"+this.nameString);
		flag=false;
		//notifyAll();
                condition.signalAll();
	}

//这样子功能没有变化,与之前一致。
//------------------------------------------------
//下面是优化后
	
//若通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。(则可体现优化所在:一个锁可以显加上多组监视器)
	Condition producer_con = lock.newCondition();//监听生产者
	Condition consumer_con = lock.newCondition();//监听消费者

public  void out() {//与上面的格式进行对比
		lock.lock();
		try {
			while(!flag)
				try {
					consumer_con.await(); //指定沉睡一个消费者的线程
				} catch ( InterruptedException e) {
				}
			System.out.println(Thread.currentThread().getName()+"。消费者。。。。。。"+this.nameString+count);
			flag=false;
			producer_con.signal();//指定唤醒一个生产者的线程
		} finally {
			lock.unlock();
		}
	}


wait 和 sleep 区别?

1,wait可以指定时间也可以不指定。
   sleep必须指定时间。

2,在同步中时,对cpu的执行权和锁的处理不同。
    wait:释放执行权,释放锁。
    sleep:释放执行权,不释放锁。
 

停止线程

run方法结束。

怎么控制线程的任务结束呢?
任务中都会有循环结构,只要控制住循环就可以结束任务。

控制循环通常就用定义标记来完成。

但是如果线程处于了冻结状态,无法读取标记。如何结束呢?

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

但是强制动作会发生了InterruptedException,记得要处理

守护线程

可以理解为后台线程,前台线程结束时,守护线程(后台线程)自动结束。

 

 

线程优先级

t2.setPriority(Thread.MAX_PRIORITY);

创建线程默认优先级为5(1到10,优先级越大越有利,但同样需要去抢占CPU资源)

 

 

 

 

发布了38 篇原创文章 · 获赞 6 · 访问量 1928

猜你喜欢

转载自blog.csdn.net/weixin_43827227/article/details/96982701