黑马程序员----多线程3



等待唤醒机制:

涉及的方法:

1,wait();让线程处于冻结状态,被wait的线程会被存到线程池中。(线程池到底又是个什么东西!)

2,notify();唤醒线程池中一个线程(任意)。

3,notifyAll();唤醒线程池中全部线程。

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

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


wait();是用来操作线程的,但是居然不在线程类里面。为什么在Object里面?

为什么操作线程的方法wait(),notify(),notifyall定义在了object类里面?

原因是:因为这些是监视器的方法,监视器其实就是锁。而锁呢?可是是任意对象嘛,任意的对象调用的方式一定是定义在Object类中。

所谓的对象监视器-----就是锁


要求理解这个图。

唤醒机制练习:

/*
唤醒机制练习:

思想:

1,建立资源对象,资源对象有资源,就向外提供get 与 set 方法。

2,输入、输出资源方法,是对资源同时进行的方法,用到多线程,实现Runnable

*/
//建立资源对象
class Resource
{
	private String name; 
	private String sex; 
	private boolean flag = false;//用于线程冻结与唤醒标志位
	
	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
{
	Resource r ;

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

	public void run()
	{
		int x = 0;//取模判断用于切换模式
		while(true)
		{
			if(x == 0)
			{
				r.set("张山....","男");
			}
			else
			{
				r.set("媛媛.......","女");

			}
			x = x++%2;
		}

	}
}

//描述输出对象
class Output implements Runnable
{
	Resource r ;
	Output(Resource r)
	{
		this.r = r; 
	}

	public void run()
	{
		r.out();
	}

}
}

class ResourceDemo 
{
	public static void main(String[] args) 
	{
		//System.out.println("Hello World!");

		// 创建资源
		Resource r = new Resource();

		// 创建任务
		Input in = new Input(r);
		Output out = new Output(r);

		//创建线程
		Thread t = new Thread(in);
		Thread t1 = new Thread(out);
		//开启线程
		t.start();
		t1.start();

	}
}


来多生产者,多消费者实例:


线程安全隐患出现,一但出现线程安全隐患,考虑有没有共享数据。


/*
生产者,消费者。

多生产者,多消费者的问题。
if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。
while判断标记,解决了线程获取执行权后,是否要运行!

notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。
notifyAll解决了本方线程一定会唤醒对方线程的问题。


*/

class Resource
{
	private String name;
	private int count = 1;
	private boolean flag = false;
	public synchronized void set(String name)//  
	{
		while(flag)
			//if(flag) //导致线程错过消费的问题点if语句,冻结后继续往下执行,不再判断而导致的问题。
			//重点了解if和while的区别
			try{this.wait();}catch(InterruptedException e){}//   t1    t0
		
		this.name = name + count;//烤鸭1  烤鸭2  烤鸭3
		count++;//2 3 4
		System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
		flag = true;
		notifyAll();//为了能唤醒消费的线程。
		//notify();
	}

	public synchronized void out()//  t3
	{
		while(!flag)
			//if(!flag)
			try{this.wait();}catch(InterruptedException e){}	//t2  t3
		System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);//消费烤鸭1
		flag = false;
		notifyAll();
		//notify();

	}
}

class Producer implements Runnable
{
	private Resource r;
	Producer(Resource r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.set("烤鸭");
		}
	}
}

class Consumer implements Runnable
{
	private Resource r;
	Consumer(Resource r)
	{
		this.r = r;
	}
	public void 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();

	}
}


多线程(线程间通信-多生产者多消费者问题-JDK1.5新特性-Lock)---------为了解决notifyAll ();

说说把锁封装成对象的原因,以前synchronized是隐式的锁!现在什么时候释放,什么时候锁,都是我们自己说了算!


Condition接口中的方法有自己的实现方法!

以前痛苦的地方就是一个锁上只有一组监视器,这组监视器即监视着生产者又监视着消费者。(其实这里就是解决notifyAll();的方法)

现在考虑:现在可以生产者和消费者都具备一套监视器

问题:以前也可以弄啊?但是是生产者和消费者持有不同的锁才行。

实现方法:




API实例(要求能自己写):

 class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length) 
         notFull.await();
       items[putptr] = x; 
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0) 
         notEmpty.await();
       Object x = items[takeptr]; 
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   } 
 }

要求熟悉的例子:

/*
jdk1.5以后将同步和锁封装成了对象。 
并将操作锁的隐式方式定义到了该对象中,
将隐式动作变成了显示动作。

Lock接口: 出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。
同时更为灵活。可以一个锁上加上多组监视器。
lock():获取锁。
unlock():释放锁,通常需要定义finally代码块中。


Condition接口:出现替代了Object中的wait notify notifyAll方法。
			将这些监视器方法单独进行了封装,变成Condition监视器对象。
			可以任意锁进行组合。
await();
signal();
signalAll();



*/

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)//  t0 t1
	{
		lock.lock();
		try
		{
			while(flag)
//			try{lock.wait();}catch(InterruptedException e){}//   t1    t0
			try{producer_con.await();}catch(InterruptedException e){}//   t1    t0
		
			this.name = name + count;//烤鸭1  烤鸭2  烤鸭3
			count++;//2 3 4
			System.out.println(Thread.currentThread().getName()+"...生产者5.0..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
			flag = true;
//			notifyAll();
//			con.signalAll();
			consumer_con.signal();
		}
		finally
		{
			lock.unlock();
		}
		
	}

	public  void out()// t2 t3
	{
		lock.lock();
		try
		{
			while(!flag)
//			try{this.wait();}catch(InterruptedException e){}	//t2  t3
			try{cousumer_con.await();}catch(InterruptedException e){}	//t2  t3
			System.out.println(Thread.currentThread().getName()+"...消费者.5.0......."+this.name);//消费烤鸭1
			flag = false;
//			notifyAll();
//			con.signalAll();
			producer_con.signal();
		}
		finally
		{
			lock.unlock();
		}
		
	}
}

class Producer implements Runnable
{
	private Resource r;
	Producer(Resource r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.set("烤鸭");
		}
	}
}

class Consumer implements Runnable
{
	private Resource r;
	Consumer(Resource r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.out();
		}
	}
}



class  ProducerConsumerDemo2
{
	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();

	}
}


wait(); 和sleep();的区别?

1,wait(); 可以指定时间也可以不指定。(也就是说wait可以是无休止的)

sleep必须指定时间。

2,在同步中时,对cpu的执行权和锁的处理不同。

wait();释放执行权,释放锁

sleep();释放执行权,不释放锁。(这不需要人叫,自己可以醒)



线程什么时候消亡呢?



停止线程方式一:定义标记(有解决不了的问题的时候,是什么呢?)

答案:如果线程处于冻结状态,就不会有机会判断标志位了。那又怎么结束呢?


停止线程:
1,stop方法。
2,run方法结束。

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

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


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


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


当时强制动作会发生了InterruptedException,记得要处理



线程可以调节优先级!


多线程总结:

1,进程和线程的概念。
	|--进程:
	|--线程:

2,jvm中的多线程体现。
	|--主线程,垃圾回收线程,自定义线程。以及他们运行的代码的位置。

3,什么时候使用多线程,多线程的好处是什么?创建线程的目的?
	|--当需要多部分代码同时执行的时候,可以使用。

4,创建线程的两种方式。★★★★★
	|--继承Thread
		|--步骤
	|--实现Runnable
		|--步骤
	|--两种方式的区别?

5,线程的5种状态。
	对于执行资格和执行权在状态中的具体特点。
	|--被创建:
	|--运行:
	|--冻结:
	|--临时阻塞:
	|--消亡:

6,线程的安全问题。★★★★★
	|--安全问题的原因:
	|--解决的思想:
	|--解决的体现:synchronized
	|--同步的前提:但是加上同步还出现安全问题,就需要用前提来思考。
	|--同步的两种表现方法和区别:
	|--同步的好处和弊端:
	|--单例的懒汉式。
	|--死锁。
	

7,线程间的通信。等待/唤醒机制。
	|--概念:多个线程,不同任务,处理同一资源。 
	|--等待唤醒机制。使用了锁上的 wait notify notifyAll.  ★★★★★
	|--生产者/消费者的问题。并多生产和多消费的问题。  while判断标记。用notifyAll唤醒对方。 ★★★★★
	|--JDK1.5以后出现了更好的方案,★★★
		Lock接口替代了synchronized  
		Condition接口替代了Object中的监视方法,并将监视器方法封装成了Condition
		和以前不同的是,以前一个锁上只能有一组监视器方法。现在,一个Lock锁上可以多组监视器方法对象。
		可以实现一组负责生产者,一组负责消费者。 
	|--wait和sleep的区别。★★★★★

	

8,停止线程的方式。
	|--原理:
	|--表现:--中断。

9,线程常见的一些方法。
	|--setDaemon()
	|--join();
	|--优先级
	|--yield();
	|--在开发时,可以使用匿名内部类来完成局部的路径开辟。 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值