论坛首页 Java企业应用论坛

java并发线程-----阻塞队列的实现和思考

浏览 17455 次
精华帖 (3) :: 良好帖 (0) :: 新手帖 (2) :: 隐藏帖 (6)
作者 正文
   发表时间:2011-07-05  
楼主的逻辑思维能力确实不错,尤其是在实践经验不多的情况下,就能分析出可能出现的死锁。
会用blockingqueue和会写blocingqueue是不一样的,鼓励楼主继续研究。
0 请登录后投票
   发表时间:2011-07-05   最后修改:2011-07-05
taolei0628 写道
楼主的逻辑思维能力确实不错,尤其是在实践经验不多的情况下,就能分析出可能出现的死锁。
会用blockingqueue和会写blocingqueue是不一样的,鼓励楼主继续研究。

谢鼓励 哈哈
0 请登录后投票
   发表时间:2011-07-05  
AngelAndAngel 写道
taolei0628 写道
楼主的逻辑思维能力确实不错,尤其是在实践经验不多的情况下,就能分析出可能出现的死锁。
会用blockingqueue和会写blocingqueue是不一样的,鼓励楼主继续研究。


这东西实践经验确实不多 主要是用的机会不太多 没有遇到过太复杂的东西 我也相当于学习了 光用的话LinkedBlockingQueue确实不难。

0 请登录后投票
   发表时间:2011-07-05  
AngelAndAngel 写道
samttsch 写道
public class BlockingQ
{
    private Object notEmpty = new Object();
    private Object notFull = new Object();
    private Queue<Object> linkedList = new LinkedList<Object>();
    private int maxlength = 10;
   
    public Object take() throws InterruptedException{
        synchronized (notEmpty){
            if(linkedList.size()==0) {
                notEmpty.wait();
            }
            synchronized (notFull){
                if(linkedList.size() == maxlength){
                    notFull.notifyAll();
                }
                return linkedList.poll();
            }
        }
    }
   
    public Object offer(Object object) throws InterruptedException{
        synchronized (notEmpty){
            if(linkedList.size()==0) {
                notEmpty.notifyAll();
            }
            synchronized (notFull){
                if(linkedList.size() == maxlength){
                    notFull.wait();
                }
                return linkedList.add(object);
            }
        }
    }
}

  这段代码是死锁的示例代码。哈哈。当A线程到达take的时候,发觉linkedList.size()==0,然后开始wait,等待释放notEmpty上的锁,这个时候B线程到达offer,开始add,add了几次后,发觉已到上线,然后wait,等待释放notFull上的锁,但是要释放notFull上的锁,必须要先进入take的notEmpty锁,而notEmpty锁,也在等待offer中的notEmpty锁释放,ok,死了。所以你这段代码是不行滴。


请你亲自测试过在发表意见,不要随便看看就下结论,尤其是连代码都还没看清楚

take:
synchronized (notEmpty){
            if(linkedList.size()==0) {   ///A 进入到这里发现没有,则等待
                notEmpty.wait();
            }
            synchronized (notFull){
                if(linkedList.size() == maxlength){
                    notFull.notifyAll();
                }
                return linkedList.poll();
            }
        }


offer:
synchronized (notEmpty){
            if(linkedList.size()==0) { //B 进入到这里 发现没有数据,唤醒A,A等待CPU
                notEmpty.notifyAll();
            }
            synchronized (notFull){
                if(linkedList.size() == maxlength){
                    notFull.wait();
                }
                return linkedList.add(object);
            }
        }

0 请登录后投票
   发表时间:2011-07-05  
samttsch 写道
AngelAndAngel 写道
samttsch 写道
public class BlockingQ
{
    private Object notEmpty = new Object();
    private Object notFull = new Object();
    private Queue<Object> linkedList = new LinkedList<Object>();
    private int maxlength = 10;
   
    public Object take() throws InterruptedException{
        synchronized (notEmpty){
            if(linkedList.size()==0) {
                notEmpty.wait();
            }
            synchronized (notFull){
                if(linkedList.size() == maxlength){
                    notFull.notifyAll();
                }
                return linkedList.poll();
            }
        }
    }
   
    public Object offer(Object object) throws InterruptedException{
        synchronized (notEmpty){
            if(linkedList.size()==0) {
                notEmpty.notifyAll();
            }
            synchronized (notFull){
                if(linkedList.size() == maxlength){
                    notFull.wait();
                }
                return linkedList.add(object);
            }
        }
    }
}

  这段代码是死锁的示例代码。哈哈。当A线程到达take的时候,发觉linkedList.size()==0,然后开始wait,等待释放notEmpty上的锁,这个时候B线程到达offer,开始add,add了几次后,发觉已到上线,然后wait,等待释放notFull上的锁,但是要释放notFull上的锁,必须要先进入take的notEmpty锁,而notEmpty锁,也在等待offer中的notEmpty锁释放,ok,死了。所以你这段代码是不行滴。


请你亲自测试过在发表意见,不要随便看看就下结论,尤其是连代码都还没看清楚

take:
synchronized (notEmpty){
            if(linkedList.size()==0) {   ///A 进入到这里发现没有,则等待
                notEmpty.wait();
            }
            synchronized (notFull){
                if(linkedList.size() == maxlength){
                    notFull.notifyAll();
                }
                return linkedList.poll();
            }
        }


offer:
synchronized (notEmpty){
            if(linkedList.size()==0) { //B 进入到这里 发现没有数据,唤醒A,A等待CPU
                notEmpty.notifyAll();
            }
            synchronized (notFull){
                if(linkedList.size() == maxlength){
                    notFull.wait();
                }
                return linkedList.add(object);
            }
        }



这段代码我刚试验过了 发生死锁了 不信你试试 。还有根据你的注释,B进入后虽然唤醒A,但是由于下面将要出现的wait,仍然没有释放,所以B仍然不会得到。
0 请登录后投票
   发表时间:2011-07-05  
将你的测试代码贴上来
0 请登录后投票
   发表时间:2011-07-05  
samttsch 写道
将你的测试代码贴上来

我的代码如下:


public class BlockOperator1 extends BlockOperator {

	private Object notEmpty = new Object();
	private Object notFull = new Object();
	private int maxlength = 3;
	private Queue<Object> linkedList = new LinkedList<Object>();

	/**
	 * 取物品
	 * 
	 * @return
	 * @throws InterruptedException
	 */
	public Object take() throws InterruptedException {
		synchronized (notEmpty) {
			String cureadname = Thread.currentThread().getName();
			System.out.println("搬运工" + cureadname + "来到仓库");
			sleep(1000l);
			if (linkedList.size() == 0) {
				// 假如仓库没东西了,那么就先不取物品,此时释放锁,被唤醒之前,需要先得到锁
				System.out.println("搬运工" + cureadname + "发觉没有物品,只能等待生产");
				notEmpty.wait();
			}
			synchronized (notFull) {
				if (linkedList.size() == maxlength) {
					notFull.notifyAll();
				}
				Object obj = linkedList.poll();
				System.out.println("搬运工" + cureadname + "这时看到有了物品,搬出了:" + obj
						+ "仓库还有物品数量:" + linkedList.size());
				return obj;
			}

		}
	}

	// 生产物品
	public void offer(Object object) throws InterruptedException {
		synchronized (notEmpty) {
			String cureadname = Thread.currentThread().getName();
			System.out.println("生产工" + cureadname + "来到仓库准备放物品");
			sleep(3000l);
			if (linkedList.size() == 0) {
				// 假如仓库没东西了,唤醒对象锁。分析:这个时候有可能没有等待锁,也可能有。
				System.out.println("生产工" + cureadname
						+ "发现来到仓库的时候一件物品都没有,发觉搬运工在睡觉等他或者感觉搬运工在等他,于是喊醒了它");
				notEmpty.notifyAll();
				/*
				 * 注 假如仓库有东西,那么不用唤醒搬运工,因为有物品的时候,搬运工不会等待。
				 * 分析:有的人肯定会觉得,有没有这种可能:当linkedList.size=0的时候,notEmpty就wait了,然后在本同步块中,
				 * 发现linkedList.size!=0,那么notEmpty就不会去唤醒了。其实这完全没有可能,因为size!=0只有在完成了
				 * linkedList.add之后才有可能,而在add之前,必然会判断size=0的情况
				 */
			}
			synchronized (notFull) {
				if (linkedList.size() == maxlength) {
					System.out.println("生产工" + cureadname + "发觉已到上线 notFull等待" );
					notFull.wait();
				}
				System.out.println("生产工" + cureadname + "把物品" + object
						+ "放到了仓库");
				linkedList.add(object);
			}

		}
	}

	private void sleep(Long time) {
		try {
			Thread.sleep(time);// 模拟时间消耗
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}


0 请登录后投票
   发表时间:2011-07-05  
你说的是对的,确实有问题!!!

public class BlockingQ {

private Object notEmpty = new Object();
private Object notFull = new Object();
private Queue linkedQueue = new LinkedList();
private int maxlength = 3;

public Object get() throws InterruptedException{
System.out.println("准备取出");
synchronized (notEmpty) {
System.out.println("获得notEmpty锁");
if(linkedQueue.size() == 0){
System.out.println("队列为空。。等待");
notEmpty.wait();
}
synchronized (notFull) {
System.out.println("是否还保留notEmpty锁 "+Thread.holdsLock(notEmpty));
System.out.println("获得notFull锁");
if(linkedQueue.size() == maxlength){
System.out.println("队列满 通知放入的线程");
notFull.notifyAll();
}
System.out.println("取出一个");
return linkedQueue.poll();
}
}

}

public void offer(Object obj) throws InterruptedException{
System.out.println(" 准备放入");
synchronized (notEmpty) {
System.out.println(" 获得notEmpty锁");
if(linkedQueue.size() == 0){
System.out.println(" 队列为空。。通知");
notEmpty.notifyAll();
}
synchronized (notFull) {
System.out.println(" 是否还保留notEmpty锁 "+Thread.holdsLock(notEmpty));
System.out.println(" 获得notFull锁");
if(linkedQueue.size() == maxlength){
System.out.println(" 等待取出的线程");
notFull.wait();
}
System.out.println(" 放入一个");
linkedQueue.add(obj);
}
}
}


static class GetWorker implements Runnable {
BlockingQ queue = null;

GetWorker(BlockingQ q){
this.queue = q;
}
public void run(){
while(true){
try {
queue.get();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

static class PutWorker implements Runnable {
BlockingQ queue = null;

PutWorker(BlockingQ q){
this.queue = q;
}
public void run(){
while(true){
try {
queue.offer(new Object());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

public static void main(String[] args) {
BlockingQ  q = new BlockingQ();

new Thread(new GetWorker(q)).start();
new Thread(new PutWorker(q)).start();
}
}

经过测试发现,线程在“内部锁”处等待时,“外部锁”是不会释放的,所以当队列满了之后会出现死锁的情况。
0 请登录后投票
   发表时间:2011-07-05  
建议还是用并发包中的类吧,自己写还是不保险
0 请登录后投票
   发表时间:2011-07-05  
samttsch 写道
建议还是用并发包中的类吧,自己写还是不保险

恩 那是。

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics