}
}
synchronized (a) { }
System.out.println(\获得对象a的锁\try { }
catch (InterruptedException e) { }
synchronized (b) { }
System.out.println(\获得对象b的锁\try { }
Thread.sleep(1); e.printStackTrace();
} catch (InterruptedException e) { e.printStackTrace(); Thread.sleep(1);
package com.px1987.j2se.thread.DeadLock; class Thread2 implements Runnable {
private Object a; private Object b;
public Thread2(Object a, Object b) { }
public void run() {
synchronized (b) {
System.out.println(\获得对象b的锁\try { }
catch (InterruptedException e) { }
synchronized (a) {
System.out.println(\获得对象a的锁\try { }
Thread.sleep(1); e.printStackTrace();
} catch (InterruptedException e) { e.printStackTrace(); Thread.sleep(1);
super(); this.a = a; this.b = b;
}
}
}
}
package com.px1987.j2se.thread.DeadLock; public class TestDeadLock { }
public static void main(String[] args) { }
Object a=new Object(); Object b=new Object();
Thread thread1=new Thread(new Thread1(a,b)); Thread thread2=new Thread(new Thread2(a,b)); thread1.start(); thread2.start();
下面是运行结果:
(2)死锁问题的另一个代码示例
package com.px1987.j2se.thread.DeadLock; public class ThreadDeadLock { }
class ThreadOne extends Thread{
String op1; String op2;
public void run(){// 同步中又有同步,就可能死锁
synchronized(op1){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+\锁定op1\
public static void main(String[] args) { }
ThreadOne threadOne=new ThreadOne(); ThreadTwo threadTwo=new ThreadTwo(); String s1=\String s2=\threadOne.op1=s1; threadTwo.op1=s1; threadOne.op2=s2; threadTwo.op2=s2; threadOne.start(); threadTwo.start();
}
}
}
}
e.printStackTrace();
synchronized(op2){ }
System.out.println(Thread.currentThread().getName()+\锁定op2\
class ThreadTwo extends Thread{ }
String op1; String op2; public void run(){ }
synchronized(op2){ }
System.out.println(Thread.currentThread().getName()+\锁定op2\try { }
synchronized(op1){ }
Thread.sleep(1000); e.printStackTrace();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+\锁定op1\
6.6生产者消费者问题
1、生产者消费者问题的示例
生产者消费者问题也是一个典型的线程问题。我们举一个这方面的实例来说明:在一个果园里,有农夫和小孩,农夫会不停的采摘水果放入果园中心的一个水果筐直到水果筐满,而小孩会不停的从水果筐里拿水果来吃,直到水果拿完。分析这个模型我们可以看出:农夫可以看成是一个生产者的线程,小孩可以看成是一个消费者的线程,而大水果筐是共享资源。 2、用Java程序表述的代码示例
package com.px1987.j2se.thread.ProducerConsumer; import java.util.Random; /*** 水果类*/
public class Fruit {
/*** 水果编号*/ private int id; /*** 水果编号计数器*/
private static int number = 0; /*** 水果品种 */
}
private String variety; /*** 水果品种数组 */
private String[] varietys = \苹果,桃子,梨子,香蕉,西瓜,荔枝,葡萄\public Fruit() { }
super();
this.variety = varietys[new Random().nextInt(7)]; this.id = ++number;
水果筐应该设计成类似于栈的数据结构,其中包含一个数组来存放筐里的水果,而数组的下标就是水果筐的容量。设定一个索引index表示指向下一个将要放入水果的位置。类中的push方法模拟农夫向水果筐中放入水果,pop方法模拟小孩从水果筐中拿水果。这两个方法都要操作共享资源,所以push和pop方法都是同步互斥方法。 3、如何避免出现死锁
那同步的问题解决后是否会出现死锁呢?大家试想一下,如果生产的速度大于消费的速度就会导致功大于求,水果筐很容易就满了,然而生产者又一直抱着水果筐不放,没有机会给消费者使用,消费者不消费生产者就无法生产,所以就造成了死锁。
怎样解决呢?在两个同步互斥方法中用到了wait和notify方法,这两个方法是为了防止死锁的。
? wait是Object类的方法,它的作用是拥有互斥锁的线程放弃锁的使用权,进入
wait池进行等待,那么互斥锁就有可能被其他线程获得以执行其他任务。
? notify也是Object类的方法,它的作用是从wait池中唤醒一条正在等待的线
程进入就绪状态,被唤醒的这条线程就很可能重新获得cup和互斥锁来完成它的任务。
? notifyAll和Notify很相似,它是从wait池中唤醒所有正在等待的线程进入就
绪状态。
需要注意的是以上三个方法都只能在synchronized方法中应用,否者会出现下面的异常信息:IllegalMonitorStateException:current thread not owner。 4、实现的代码示例
package com.px1987.j2se.thread.ProducerConsumer; import java.text.DecimalFormat; import java.util.Arrays; /*** 水果框类,类似一个栈的模型 */ public class FruitBasket {
/*** 容量为10的水果数组,也就是说水果框最多能放下10个水果 private Fruit[] fruits = new Fruit[10]; /*** 下一个将要放入水果的位置*/ private int index = 0;
/*** 水果框中是否为空 @return true为空,false为不空 */ public boolean isEmpty() { }
return index == 0 ? true : false;
*/
*/ */
/*** 水果框是否装满* @return true为满,false为未满*/ public boolean isFull() { }
/*** 进栈方法,模拟农夫把水果放入筐中,@param name 农夫的名字,@param fruit 水果对象 public synchronized void push(String name, Fruit fruit) { }
/*** 出栈方法,模拟小孩从水果筐中取出水果,@param name 小孩的名字,@return 取出的水果public synchronized Fruit pop(String name) { }
//用while循环,不用if,避免IndexOutOfBoundsException异常的产生 while (isEmpty()) { }
Fruit fruit = null;
//index下移一位,取出指示位置上的水果
try { }
catch (InterruptedException e) { }
e.printStackTrace(); this.wait();
//如果水果筐空,需要等待
//用while循环,不用if,避免IndexOutOfBoundsException异常的产生 while (isFull()) { }
//将水果放入index指示的位置,index再上移一格 fruits[index++] = fruit;
System.out.println(name + \向水果框中放入编号为\的\
fruit.getVariety());
display();
//如果水果筐满了,需要等待 try { }
catch (InterruptedException e) { }
e.printStackTrace(); this.wait();
return index == fruits.length ? true : false;
this.notify(); //通知其他等待的农夫或孩子可以开始工作啦
fruit = fruits[--index];
System.out.println(name + \从水果框中拿出编号为\的\
fruit.getVariety());
display(); this.notify(); return fruit;