java解惑――易错知识点归纳总结 (五)

2014-11-24 09:26:36 · 作者: · 浏览: 14
ist.size() <= 0) {
wait();
}
return list.removeLast();
}
}
}

//例1 线程同步
class SyncStack{ //同步堆栈类
   private int index = 0; //堆栈指针初始值为0
   private char []buffer = new char[6]; //堆栈有6个字符的空间
   public synchronized void push(char c){ //加上互斥锁
     while(index = = buffer.length){ //堆栈已满,不能压栈
     try{
        this.wait(); //等待,直到有数据出栈
       }catch(InterruptedException e){}
    }
    this.notify(); //通知其它线程把数据出栈
    buffer[index] = c; //数据入栈
    index++; //指针向上移动
   }
   public synchronized char pop(){ //加上互斥锁
       while(index ==0){ //堆栈无数据,不能出栈
        try{
           this.wait(); //等待其它线程把数据入栈
        }catch(InterruptedException e){}
    }
       this.notify(); //通知其它线程入栈
       index- -; //指针向下移动
       return buffer[index]; //数据出栈
    }
 }
    class Producer implements Runnable{ //生产者类
       SyncStack theStack;
        //生产者类生成的字母都保存到同步堆栈中

       public Producer(SyncStack s){
          theStack = s;
       }
       public void run(){
          char c;
          for(int i=0; i<20; i++){
            c =(char)(Math.random()*26+'A');  //随机产生20个字符
            theStack.push(c); //把字符入栈
            System.out.println("Produced: "+c); //打印字符
            try{
             Thread.sleep((int)(Math.random()*1000)); /*每产生一个字符线程就睡眠*/
            }catch(InterruptedException e){}
          }
       }
     }
     class Consumer implements Runnable{ //消费者类
         SyncStack theStack;  //消费者类获得的字符都来自同步堆栈
         public Consumer(SyncStack s){
             theStack = s;
         }
         public void run(){
             char c;
             for(int i=0;i<20;i++){
               c = theStack.pop(); //从堆栈中读取字符
             System.out.println("Consumed: "+c);  //打印字符
  try{
              Thread.sleep((int)(Math.random()*1000));
             }catch(InterruptedException e){}
         }
       }
     }
     public class SyncTest{
       public static void main(String args[]){
         SyncStack stack = new SyncStack();
   //下面的消费者类对象和生产者类对象所操作的是同一个同步堆栈对象
         Runnable source=new Producer(stack);
         Runnable sink = new Consumer(stack);
         Thread t1 = new Thread(source); //线程实例化
         Thread t2 = new Thread(sink); //线程实例化
         t1.start(); //线程启动
         t2.start(); //线程启动
       }
     }
//例2.下面的代码在绝大部分时间内都运行得很正常,请问在什么情况下会出现问题?问题的根源在哪里?
import java.util.LinkedList;
public class Stack {
LinkedList list = new LinkedList();

public synchronized void push(Object x) {
synchronized (list) {
list.addLast(x);
notify();
}
}

public synchronized Object pop() throws Exception {
synchronized (list) {
if (list.size() <= 0) {
wait();
}
return list.removeLast();
}
}
}
对例2的分析【网友】:
当一个线程执行下面方法:
[java] view plaincopyprint public synchronized void push(Object x) {
synchronized(list) {
list.addLast( x );
notify();
}
}

public synchronized void push(Object x) {
synchronized(list) {
list.addLast( x );
notify();
}
}
这个时候他获得2个锁,一个是Stack对象的锁,还有list对象的锁,而notify,释放的是stack对象的锁,没有释放list对象的锁,所以只要当pop方法中检测到list的大小为0,则执行pop的线程会一直控制list的锁,使得push没法执行。 之所以大部分时间程序运行成功,是因为push总比pop快,list没有为0.

[java]
//例3.可能死锁的线程
public class SyncTest {
public static void main(String[] args) {
final StringBuffer s1 = new StringBuffer();
final StringBuffer s2 = new StringBuffer();
new Thread() {
public void run() {
synchronized (s1) {
s2.append("A");
synchronized (s2) {
s2.append("B");
System.out.print(s1);
System.out.print(s2);
}
}
}
}.start();

new Thread() {
public void run() {
synchronized (s2) {
s2.append("