问一个线程同步的问题

本贴最后更新于 2773 天前,其中的信息可能已经事过境迁

上代码:

import  java.util.LinkedList;
import java.util.Queue;

class BlockingQ {
    private Object notEmpty = new Object();
    private Object notFull = new Object();
    private Queue linkedList = new LinkedList();
    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 void offer(Object object) throws InterruptedException {
        synchronized (notEmpty) {
            if (linkedList.size() == 0) {
                notEmpty.notifyAll();
            }
            synchronized (notFull) {
                if (linkedList.size() == maxLength) {
                    notFull.wait();
                }
                linkedList.add(object);
            }
        }
    }
}

有点不懂, notFull.wait(); 会释放 notEmpty 吗? 谁能简单的讲讲。


更新:做了个测试,发现确实是会阻塞的,上面的阻塞队列实现有问题:

public class BlockingQTest {
	public static void main(String [] as) throws InterruptedException {
		BlockingQ blockingQ = new BlockingQ();
		Thread offerThread = new Thread(new OfferTask(blockingQ),"offerThread");
		Thread takeThread = new Thread(new TakeTask(blockingQ),"takeThread");
		offerThread.start();
		takeThread.start();
	}
}

class TakeTask implements Runnable{
	private BlockingQ blockingQ;
	public TakeTask(BlockingQ blockingQ){
		this.blockingQ = blockingQ;
	}
	@Override
  public void run() {
		try {
			while(true) {
				Object o = blockingQ.take();
				System.out.println("take:" + o);
				Thread.sleep(1000);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
class OfferTask implements Runnable{
	private BlockingQ blockingQ;
	public OfferTask(BlockingQ blockingQ){
		this.blockingQ = blockingQ;
	}
	@Override
  public void run() {
		try {
			for (int i=0; i < 20; i++){
				blockingQ.offer(i);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

下面这个实现是没问题的:

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import  java.util.concurrent.locks.ReentrantLock;

class BlockingQ {
	private Lock lock = new ReentrantLock();
	private Condition notEmpty = lock.newCondition();
	private Condition notFull = lock.newCondition();
	private Queue linkedList = new LinkedList();
	private int maxLength = 10;
	public Object take() throws InterruptedException {
		lock.lock();
		try {
			if (linkedList.size() == 0) {
				notEmpty.await();
			}
			if (linkedList.size() == maxLength) {
				notFull.signalAll();
			}
			return linkedList.poll();
		} finally {
			lock.unlock();
		}
	}
	public void offer(Object object) throws InterruptedException {
		lock.lock();
		try {
			if (linkedList.size() == 0) {
				notEmpty.signalAll();
			}
			if (linkedList.size() == maxLength) {
				notFull.await();
			}
			linkedList.add(object);
			System.out.println("offer:" + object);
		} finally {
			lock.unlock();
		}
	}
}

附上代码来源的截图:

a771005f4fcd44908c9c451d76a0ee44.png

80f4a8ced57a417eab05f113976a68c1.png

资料:
http://files.cnblogs.com/files/jobs/Java%E5%B9%B6%E5%8F%91%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E6%95%99%E7%A8%8B.pdf

  • 多线程
    11 引用 • 26 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • qwab16

    不会释放 notEmpty,只会释放自己 notFull 的锁

    1 回复
  • 那这个简单的阻塞队列实现就有问题了啊
    offer 的 notEmpty 如果不会释放
    那 take 如何进入 notEmpty 呢?

    1 回复
  • qwab16

    同步的那段代码块执行完了就会释放,平不影响 take 执行

    2 回复
  • 我做了个测试:

    public class BlockingQTest {
    	public static void main(String [] as) throws InterruptedException {
    		BlockingQ blockingQ = new BlockingQ();
    		Thread offerThread = new Thread(new OfferTask(blockingQ), "offerThread");
    		Thread takeThread = new Thread(new TakeTask(blockingQ), "takeThread");
    		offerThread.start();
    		takeThread.start();
    	}
    }
    
    class TakeTask implements Runnable{
    	private BlockingQ blockingQ;
    	public TakeTask(BlockingQ blockingQ){
    		this.blockingQ = blockingQ;
    	}
    	@Override
      public void run() {
    		try {
    			Object o = blockingQ.take();
    			System.out.println("take:" + o);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    class OfferTask implements Runnable{
    	private BlockingQ blockingQ;
    	public OfferTask(BlockingQ blockingQ){
    		this.blockingQ = blockingQ;
    	}
    	@Override
      public void run() {
    		try {
    			for (int i=0; i < 100; i++){
    				blockingQ.offer(i);
    			}
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    00597ee6a45948739ed062cf4883bcfe.png

    确实是不会释放锁的,我写的测试方式有问题吗 ? 死锁了

  • 纠正一下 take 漏了循环 ,只取了一次。。。。。。
    public class BlockingQTest {
    public static void main(String [] as) throws InterruptedException {
    BlockingQ blockingQ = new BlockingQ();
    Thread offerThread = new Thread(new OfferTask(blockingQ),"offerThread");
    Thread takeThread = new Thread(new TakeTask(blockingQ),"takeThread");
    offerThread.start();
    takeThread.start();
    }
    }

    class TakeTask implements Runnable{
    	private BlockingQ blockingQ;
    	public TakeTask(BlockingQ blockingQ){
    		this.blockingQ = blockingQ;
    	}
    	@Override
      public void run() {
    		try {
    			while(true) {
    				Object o = blockingQ.take();
    				System.out.println("take:" + o);
    			}
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    class OfferTask implements Runnable{
    	private BlockingQ blockingQ;
    	public OfferTask(BlockingQ blockingQ){
    		this.blockingQ = blockingQ;
    	}
    	@Override
      public void run() {
    		try {
    			for (int i=0; i < 100; i++){
    				blockingQ.offer(i);
    			}
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    
  • xjtushilei

    notEmpty.notifyAll(); 为什么不是 add 结束后。如果不结束,那么上面的 take 被唤醒了,由于 notnull 的🔒的存在并不能取到东西呀

    2 回复
  • 阿里巴巴分享的 pdf 里面就是这样写的

  • 我也不造啊。。。。

请输入回帖内容 ...

推荐标签 标签

  • Bootstrap

    Bootstrap 是 Twitter 推出的一个用于前端开发的开源工具包。它由 Twitter 的设计师 Mark Otto 和 Jacob Thornton 合作开发,是一个 CSS / HTML 框架。

    18 引用 • 33 回帖 • 659 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 399 关注
  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    21 引用 • 31 回帖 • 1 关注
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 385 关注
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 624 关注
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 638 关注
  • 星云链

    星云链是一个开源公链,业内简单的将其称为区块链上的谷歌。其实它不仅仅是区块链搜索引擎,一个公链的所有功能,它基本都有,比如你可以用它来开发部署你的去中心化的 APP,你可以在上面编写智能合约,发送交易等等。3 分钟快速接入星云链 (NAS) 测试网

    3 引用 • 16 回帖
  • 游戏

    沉迷游戏伤身,强撸灰飞烟灭。

    176 引用 • 815 回帖
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    334 引用 • 323 回帖 • 2 关注
  • Sphinx

    Sphinx 是一个基于 SQL 的全文检索引擎,可以结合 MySQL、PostgreSQL 做全文搜索,它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索。

    1 引用 • 211 关注
  • 人工智能

    人工智能(Artificial Intelligence)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门技术科学。

    133 引用 • 189 回帖
  • Telegram

    Telegram 是一个非盈利性、基于云端的即时消息服务。它提供了支持各大操作系统平台的开源的客户端,也提供了很多强大的 APIs 给开发者创建自己的客户端和机器人。

    5 引用 • 35 回帖 • 2 关注
  • Mac

    Mac 是苹果公司自 1984 年起以“Macintosh”开始开发的个人消费型计算机,如:iMac、Mac mini、Macbook Air、Macbook Pro、Macbook、Mac Pro 等计算机。

    166 引用 • 595 回帖 • 1 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 483 关注
  • 安全

    安全永远都不是一个小问题。

    199 引用 • 816 回帖
  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    58 引用 • 22 回帖
  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    543 引用 • 672 回帖
  • 反馈

    Communication channel for makers and users.

    123 引用 • 911 回帖 • 245 关注
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖
  • IPFS

    IPFS(InterPlanetary File System,星际文件系统)是永久的、去中心化保存和共享文件的方法,这是一种内容可寻址、版本化、点对点超媒体的分布式协议。请浏览 IPFS 入门笔记了解更多细节。

    21 引用 • 245 回帖 • 240 关注
  • BND

    BND(Baidu Netdisk Downloader)是一款图形界面的百度网盘不限速下载器,支持 Windows、Linux 和 Mac,详细介绍请看这里

    107 引用 • 1281 回帖 • 27 关注
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    77 引用 • 430 回帖
  • 强迫症

    强迫症(OCD)属于焦虑障碍的一种类型,是一组以强迫思维和强迫行为为主要临床表现的神经精神疾病,其特点为有意识的强迫和反强迫并存,一些毫无意义、甚至违背自己意愿的想法或冲动反反复复侵入患者的日常生活。

    15 引用 • 161 回帖
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    15 引用 • 7 回帖 • 1 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    107 引用 • 153 回帖 • 3 关注
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 588 回帖