说起BlockingQueue,大家最熟悉的就是生产者-消费者模式下的应用。但是如果在调用queue的上层代码加了同步块就会导致线程死锁。

例如:

    static BlockingQueue<String> queue = new LinkedBlockingQueue();

    /**
* 同步锁
*/
static Object lock = new Object(); static void producer(){
synchronized (lock){
queue.put("1");
}
} static void cosumer(){
synchronized (lock){
//一旦阻塞,将挂起当前线程,lock锁永远等不到释放,生产者也就无法添加元素,take也就永远阻塞
String msg = queue.take();
}
}

但是同步块必须使用的情况下,怎样改进queue的使用呢?见下面示例:

package com.hdwang;

import com.alibaba.fastjson.JSON;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; /**
* Created by hdwang on 2018/4/17.
*/
public class MultiQueueSynTest { static BlockingQueue<Packet> queue1 = new LinkedBlockingQueue(); static BlockingQueue<Packet> queue2 = new LinkedBlockingQueue(); static int seq = 1; /**
* 同步锁
*/
static Object lock = new Object(); static void commit(String msg){
synchronized (lock) {
Packet packet = new Packet();
packet.setSeq(seq++);
packet.setMsg(msg);
try { //queue1.put(packet); //阻塞式添加元素 while(queue1.size()== Integer.MAX_VALUE){ //队满,等待
lock.wait();
} queue1.offer(packet); //非阻塞式添加元素即可
System.out.println("commit msg:" + JSON.toJSONString(packet));
lock.notifyAll(); //通知等待线程 } catch (InterruptedException e) {
e.printStackTrace();
}
}
} static void send(){
while(true) {
synchronized (lock) {
try { //Packet packet = queue1.take(); //阻塞式取元素
//queue2.put(packet); while(queue1.isEmpty()) { //队空,等待
lock.wait(); //等待,交出锁
} Packet packet = queue1.poll(); //非阻塞式取元素即可
System.out.println("send msg:" + JSON.toJSONString(packet));
lock.notifyAll(); //通知等待线程 while (queue2.size() == Integer.MAX_VALUE){ //队满,等待
lock.wait(); //等待,交出锁
}
queue2.offer(packet);
System.out.println("msg->queue2:"+JSON.toJSONString(packet));
lock.notifyAll(); //通知等待线程 } catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} public static void main(String[] args) {
//生产者1
new Thread(new Runnable() {
@Override
public void run() {
while(true){ //不断产生消息
commit("hello1"); try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
//生产者2
new Thread(new Runnable() {
@Override
public void run() {
while(true){ //不断产生消息
commit("hello2"); try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start(); //消费者
new Thread(new Runnable() {
@Override
public void run() { send();
}
}).start(); } static class Packet{
int seq;
String msg; public int getSeq() {
return seq;
} public void setSeq(int seq) {
this.seq = seq;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
}
} }

运行结果

commit msg:{"msg":"hello1","seq":1}
send msg:{"msg":"hello1","seq":1}
msg->queue2:{"msg":"hello1","seq":1}
commit msg:{"msg":"hello2","seq":2}
send msg:{"msg":"hello2","seq":2}
msg->queue2:{"msg":"hello2","seq":2}
commit msg:{"msg":"hello1","seq":3}
send msg:{"msg":"hello1","seq":3}
msg->queue2:{"msg":"hello1","seq":3}
commit msg:{"msg":"hello2","seq":4}
send msg:{"msg":"hello2","seq":4}
msg->queue2:{"msg":"hello2","seq":4}
commit msg:{"msg":"hello1","seq":5}
send msg:{"msg":"hello1","seq":5}
msg->queue2:{"msg":"hello1","seq":5}
commit msg:{"msg":"hello2","seq":6}
send msg:{"msg":"hello2","seq":6}
msg->queue2:{"msg":"hello2","seq":6}

java同步代码(synchronized)中使用BlockingQueue的更多相关文章

  1. wait、notify为什么要放在同步代码块中

    等待方遵循的原则: 获取对象的锁,不满足条件就调用wait()方法,条件满足继续执行 通知方原则: 获取对象的锁,改变条件,然后notify 每个对象都有一个监视器锁,这个监视器锁的数据结构如下: w ...

  2. .NET中如何在同步代码块中调用异步方法

    更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月2日. 在同步代码块中调用异步方法,方法有很多. 一.对于有返回值的Task 在同步代码块中直接访问 Task 的 Result ...

  3. JAVA 同步之 synchronized 修饰方法

    在JAVA多线程编程中,将需要并发执行的代码放在Thread类的run方法里面,然后创建多个Thread类的对象,调用start()方法,线程启动执行. 当某段代码需要互斥时,可以用 synchron ...

  4. java 同步代码块与同步方法

    同步代码块 synchronized (obj) { // 代码块 } obj 为同步监视器,以上代码的含义为:线程开始执行同步代码块(中的代码)之前,必须先获得对同步监视器的锁定. 代码块中的代码是 ...

  5. Java 同步代码块 - Synchronized Blocks

    java锁实现原理: http://blog.csdn.net/endlu/article/details/51249156 The synchronized keyword can be used ...

  6. JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

    JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程 ...

  7. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  8. Java线程同步(synchronized)——卖票问题

    卖票问题通常被用来举例说明线程同步问题,在Java中,采用关键字synchronized关键字来解决线程同步的问题. Java任意类型的对象都有一个标志位,该标志位具有0,1两种状态,其开始状态为1, ...

  9. java并发之线程同步(synchronized和锁机制)

    使用synchronized实现同步方法 使用非依赖属性实现同步 在同步块中使用条件(wait(),notify(),notifyAll()) 使用锁实现同步 使用读写锁实现同步数据访问 修改锁的公平 ...

随机推荐

  1. Eclipse添加Junit测试

    项目上右键,点击build path->add libraaies->选择Junit 附上惨不忍睹的图(eclipse里展开菜单项时老截屏截不好,不知各位有没有好点的解决方案) 2017. ...

  2. 2017-2018-2 20155231《网络对抗技术》实验五: MSF基础应用

    2017-2018-2 20155231<网络对抗技术>实验五: MSF基础应用 实践目标 掌握信息搜集的最基础技能与常用工具的使用方法. 实验内容 (1)各种搜索技巧的应用 比如IP2L ...

  3. WPF 简易进度条效果

    最近做一个项目,看到以前同事写的进度条效果不错,所以,拿来简化了下,不炫,但是项目中还是够用的. 还是,先来看下调用以后的效果 1.因为ProgressbBar的Foreground显示不得不一样,所 ...

  4. STM32一键下载电路设计原理

    先放原理图(补充:图中的BOOT0通过10K的电阻接到地),再解释为什么这么设计: STM32启动方式:BOOT0和 BOOT1用于设置 STM32的启动方式 ,见下表: BOOT0=1,BOOT1= ...

  5. kvm虚拟化二: 字符界面管理及 无人值守安装

    1. 安装必要工具yum install / tigervnc //vnc远程桌面客户端 virt-viewer //虚拟机查看器 2.安装虚拟机virt-install / -n 名字 //虚拟机名 ...

  6. MSBUILD : error MSB3428: 未能加载 Visual C++ 组件“VCBuild.exe”

    问题 MSBUILD : error MSB3428: 未能加载 Visual C++ 组件"VCBuild.exe".要解决此问题,1) 安装 .NET Framework 2. ...

  7. C# 基于泛型的自定义线性节点链表集合示例

    本例子实现了如何自定义线性节点集合,具体代码如下: using System; using System.Collections; using System.Collections.Generic; ...

  8. android 一些常用的功能方法代码块

    我们这些苦逼的程序员在工作中,每一个老板都希望我们都能把手头的工作做好的,而且是越快越好,那我们要怎么样才能快起来呢?对于开发中常用的代码块无限复做是我们工作中简省时间最有效的途径之一,而下面的这些代 ...

  9. java批量爬取电影资源

    摘要 网上有很多个人站来分享电影资源,其实有时候我们自己也想做这个一个电影站来分享资源.但是这个时候就有一个问题,电影的资源应该从哪里来呢?难道要自己一条条手动去从网络上获取,这样无疑是缓慢而又效率低 ...

  10. Unity---Inspector面板自定义

    一. 参数自定义 一个含有成员的类Player using System.Collections; using System.Collections.Generic; using UnityEngin ...