等待唤醒(生产者与消费者)

死锁的情况

一.同步嵌套

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Dead implements Runnable
{
private boolean flag;
Dead(boolean flag)
{
this.flag = flag;
}
public void run()
{ if(flag)
{
synchronized(Mylock.lock_A)
{
System.out.println("if...A");
synchronized(Mylock.lock_B)
{
System.out.println("if...B");
}
}
}
else
{
synchronized(Mylock.lock_B)
{System.out.println("else...B");
synchronized(Mylock.lock_A)
{System.out.println("else...A");
}
}
}
}
}

class Mylock//锁
{
public static final Object lock_A = new Object();
public static final Object lock_B = new Object();
}
class Deaddemo
{
public static void main(String[] args)
{
Dead t1 = new Dead(true);
Dead t2 = new Dead(false);
new Thread(t1).start();
new Thread(t2).start();
}
}


等待唤醒机制:
wait():该方法可以让线程处于冻结状态,并将线程临时存储到线程池中。
notify():唤醒制定线程池中的任意一个线程。
notifyAll():唤醒指定线程池中的所有线程。
这些方法必须使用在同步中,因为他们用来操作同步锁上的线程的状态的。
在使用这些方法时,必须标识他们所属于的锁。标识方法就是 锁对象.wait(); 锁对象.notify(); 锁对象.notifyAll();
相同锁的notify()可以唤醒相同锁的wait();

举例一:

生产者消费者模式
模式目标:生产一个,消费一个。
*为什么使用等待唤醒机制:如果仅仅使用同步函数,会出现生产许多个才开始消费一个的情况,和现实生活不符合。

伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class 产品
{
生产()
{
if(产品已存在)
{
try{wait()}//执行wait,生产线程开始等待,此处的锁是this,所以可以省略
catch(InterruptedException e){}//使用wait需要处理异常
}
生产产品;
notify();//唤醒消费线程
}

消费()
{
if(产品不存在)
{
try{wait()}//执行wait,消费线程开始等待,此处的锁是this,所以可以省略
catch(InterruptedException e){}//使用wait需要处理异常
}
消费产品;
notify();//唤醒生产线程
}
}
class producer implements Runnable
{
private 产品 A;
producer(产品 A)
{
this.A=A;//此处是为了保证生产者和消费者操控的都是同一个对象,所以直接用构造函数获取同一个对象的实例。
}
public void run()
{
A.生产();
}
}

举例二

生产消费模式
模式目标:多个生产,多个消费,生产一个,消费一个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Product 
{
String prod;
int count=0;
boolean p=false;
public synchronized void pro()
{
while(p)
{
try
{wait();}
catch(InterruptedException e){}
}
count++;
System.out.println(Thread.currentThread().getName()+"生产面包"+count);
p=true;
notifyAll();
}
public synchronized void con()
{
while(!p)
{
try {wait();}
catch(InterruptedException e) {}
}
System.out.println(Thread.currentThread().getName()+" 消费面包"+count);
p=false;
notifyAll();
}
}

代码优化
问题是会唤醒同为生产者的其他线程
此时优化的部分是*将If改为while,这样就可以循环判断标记是否为空。

此时的问题是*如果唤醒的是同类型,那么所有线程都会中断。
此时优化的部分是*生产者生产完毕后等待,紧接着只能通过notifyAll来唤醒所有线程

 最终问题:代码效率低下,多次循环判断以及唤醒所有线程,这些都会影响程序效率。

举例三:生产消费模式

wait和sleep的区别

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

2.
wait():释放cpu资源,释放锁。

sleep():释放cpu资源,但是不释放锁。

线程停止

需要注意的是
例子:
public synchronized void run()
{
while(flag)
{
try{
wait();
}
catch(InterruptedException e )//此处抛出的异常是InterruptedException是因为
//中断一个正在wait的线程时,会收到InterruptedException异常
{
}
}
}

在其他函数中改变flag的值以达到停止的效果,如果创建多个线程执行该操作,那么程序可能会发生死锁
(因为可能main线程停止后,该线程还处于wait状态,所有此时要用到中断)

守护线程:后台线程
前台线程结束后会自动结束
join方法是等待某一线程停止
使用例子:

1
2
3
4
5
void main()
{
Thread t1 = new Thread();
t1.join();
}

此处代码的意义就是:main线程告诉CPU,结束自己的运行权限,并且等到t1运行结束后再开始运行。

优先级

setPriority()

#线程优先级有1-10等级划分

##通过 线程.setPriority() 修改线程的优先级。

Thread.yield()

#暂停该线程并执行其他线程
用处:线程交换更频繁