本章节主要简单讲下 死锁 和 线程通信
第一Part
死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
解决方法:专门的算法;尽量减少同步资源的定义;定义准确的同步资源
下边描述一个死锁的代码:
package com.thread;
public class TestDeadLock
{
static StringBuffer s1 = new StringBuffer();
static StringBuffer s2 = new StringBuffer();
public static void main(String[] args)
{
new Thread() {
public void run()
{
synchronized (s1)
{
try
{
Thread.currentThread().sleep(10);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
s2.append("A");
synchronized (s2)
{
s2.append("B");
System.out.print(s1);
System.out.print(s2);
}
}
}
}.start();
new Thread() {
public void run()
{
synchronized (s2)
{
try
{
Thread.currentThread().sleep(10);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
s2.append("C");
synchronized (s1)
{
s1.append("D");
System.out.print(s2);
System.out.print(s1);
}
}
}
}.start();
}
}
第二Part 进程通信
常用方法; wait()与notify() 和notifyAll()
wait():令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问
notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
notifyAll():唤醒正在排队等待资源的所有线程结束等待.
lJava.lang.Object提供的这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报
java.lang.IllegalMonitorStateException异常
wati()方法:
在当前线程中调用方法: 对象名.wait()
使当前线程进入等待(某对象)状态 ,直到另一线程对该对象发出 notify(或notifyAll) 为止。
调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
调用此方法后,当前线程将释放对象监控权 ,然后进入等待
在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行。
notify()/notifyAll()
在当前线程中调用方法: 对象名.notify()
功能:唤醒等待该对象监控权的一个线程。
调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
功能:唤醒等待该对象监控权的一个线程。
调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
例题:使用两个线程打印 1-100. 线程1, 线程2 交替打印
class Communication implements Runnable
{
int i = 1;
public void run()
{
while (true)
{
synchronized (this)
{
notify();
if (i <= 100)
{
System.out.println(Thread.currentThread().getName() + ":"
+ i++);
}
else
break;
try
{
wait();
}
catch (InterruptedException e)
{
}
}
}
}
}
第三part
经典例题:
生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。
这里可能出现两个问题:
生产者比消费者快时,消费者会漏掉一些数据没有取到。
消费者比生产者快时,消费者会取相同的数据。
代码案例如下:
package com.thread;
public class TestProduct
{
public static void main(String[] args)
{
Clerk clerk = new Clerk();
Thread productorThread = new Thread(new Productor(clerk));
Thread consumerThread = new Thread(new Consumer(clerk));
productorThread.start();
consumerThread.start();
}
}
class Clerk
{ // 售货员
private int product = 0;
public synchronized void addProduct()
{
if (product >= 20)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
else
{
product++;
System.out.println("生产者生产了第" + product + "个产品");
notifyAll();
}
}
public synchronized void getProduct()
{
if (this.product <= 0)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
else
{
System.out.println("消费者取走了第" + product + "个产品");
product--;
notifyAll();
}
}
}
class Consumer implements Runnable
{ // 消费者
Clerk clerk;
public Consumer(Clerk clerk)
{
this.clerk = clerk;
}
public void run()
{
System.out.println("消费者开始取走产品");
while (true)
{
try
{
Thread.sleep((int) Math.random() * 1000);
}
catch (InterruptedException e)
{
}
clerk.getProduct();
}
}
}
class Productor implements Runnable
{ // 生产者
Clerk clerk;
public Productor(Clerk clerk)
{
this.clerk = clerk;
}
public void run()
{
System.out.println("生产者开始生产产品");
while (true)
{
try
{
Thread.sleep((int) Math.random() * 1000);
}
catch (InterruptedException e)
{
}
clerk.addProduct();
}
}
}