日期:2014-05-20  浏览次数:21102 次

编写了一个线程安全:(的阻塞队列,但却出现了死锁,请高手帮忙看看,小弟多谢了
/*
编写一个线程安全、大小固定的队列
提供阻塞式的方法put,若队列没有空间,则方法put会一直等待
提供阻塞式的方法take,若队列为空,则方法take会一直等待
启动30个线程操作该队列,每个线程进行一次put和一次take操作 
*/

/*
已经按照顺序获得读锁和写锁了,但是如果启动30个线程的话,基本上每次都会死锁,线程都停在read_lock.wait()的位置,
如果启动20个线程就只有一半的几率会死锁(其实都在等待read_lock的锁,不能说是死锁),但每一个线程take一次必然会put一次,
或者反过来,按说是不会有都等待read_lock的情况
*/

package com.huawei.test;

import java.util.*;

public class Queue1
{
  final int SIZE = 10; //队列固定大小
  ArrayList store = new ArrayList(SIZE);

  Object write_lock = new Object();//用于对store的写操作,如get/add/set/remove
  Object read_lock = new Object(); //用于对store只读操作,如取size

  public Queue1(){}

  public void put (Object o) //没有空间一直等待
  {
  while(true){
  synchronized(read_lock){
  try{
  if(store.size() == SIZE){
  read_lock.wait();//如果队列已满,就释放锁
  }else{
  synchronized(write_lock){
  Thread.sleep(50);
  store.add(o); //增加元素到队列
  System.out.println(Thread.currentThread().getName() + "****PUT::Size=" + store.size());
  Thread.sleep(50);
  read_lock.notifyAll(); //通知其他线程
  break;
  }
  }
  }catch(Exception ex){
  ex.printStackTrace(System.err);
  }
  }
  }
  }


  public Object take () //没有数据一直等待
  {
  while(true){
  synchronized(read_lock){
  try{
  if(store.size() == 0){
  read_lock.wait();//如果队列没有数据,就释放锁
  }else{
  synchronized(write_lock){
  Thread.sleep(50);
  Object obj = store.remove(0); //从队列头移走数据
  System.out.println(Thread.currentThread().getName() + "****Take::Size=" + store.size());
  Thread.sleep(50);
  read_lock.notifyAll();//通知其他线程
  return obj;
  }
  }
  }catch(Exception ex){
  ex.printStackTrace(System.err);
  }
  }
  }
  }


  public static void main(String[] args){
  Queue1 queue1 = new Queue1(); //创建一个队列

  for(int i = 0; i < 30; i++){ //启动30个线程访问队列
  TestThread thread = new TestThread(queue1,i);
  System.out.println( "--Thread:" + i + " Start!" );
  thread.start();
  try{
  Thread.sleep(10); //没隔十毫秒启动一个线程
  }catch(Exception ex){
  ex.printStackTrace(System.err);
  }
  }
  }

}


class TestThread extends Thread
{
  Queue1 queue1 = null;
  int sn = 0;

  public TestThread(Queue1 queue1,int sn){
  this.queue1 = queue1;
  this.sn = sn;
  setName("Thread::" + sn); //以序号作为线程名
  }

  public void run(){
  String tmp = null;