线程阻塞

死磕 java集合之SynchronousQueue源码分析

隐身守侯 提交于 2020-03-23 16:23:15
问题 (1)SynchronousQueue的实现方式? (2)SynchronousQueue真的是无缓冲的吗? (3)SynchronousQueue在高并发情景下会有什么问题? 简介 SynchronousQueue是java并发包下无缓冲阻塞队列,它用来在两个线程之间移交元素,但是它有个很大的问题,你知道是什么吗?请看下面的分析。 源码分析 主要属性 // CPU的数量 static final int NCPUS = Runtime.getRuntime().availableProcessors(); // 有超时的情况自旋多少次,当CPU数量小于2的时候不自旋 static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32; // 没有超时的情况自旋多少次 static final int maxUntimedSpins = maxTimedSpins * 16; // 针对有超时的情况,自旋了多少次后,如果剩余时间大于1000纳秒就使用带时间的LockSupport.parkNanos()这个方法 static final long spinForTimeoutThreshold = 1000L; // 传输器,即两个线程交换元素使用的东西 private transient volatile Transferer<E>

java并发之同步辅助类CyclicBarrier

纵然是瞬间 提交于 2020-03-23 16:17:21
CyclicBarrier含义: 栅栏允许两个或者多个线程在某个集合点同步。当一个线程到达集合点时,它将调用await()方法等待其它的线程。线程调用await()方法后,CyclicBarrier将阻塞这个线程并将它置入休眠状态等待其它线程的到来。等最后一个线程调用await()方法时,CyclicBarrier将唤醒所有等待的线程然后这些线程将继续执行。CyclicBarrier可以传入另一个Runnable对象作为初始化参数。当所有的线程都到达集合点后,CyclicBarrier类将Runnable对象作为线程执行。 方法: await():使线程置入休眠直到最后一个线程的到来之后唤醒所有休眠的线程 例子 在矩阵(二维数组)中查找一个指定的数字。矩阵将被分为多个子集,每个子集交给一个线程去查找。当所有线程查找完毕后交给最后的线程汇总结果。 查找类:在一个子集中查找指定数字,找到之后把结果存储后调用await()方法置入休眠等待最后一个线程的到来唤醒 import java.util.List; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class Searcher implements Runnable {

SynchronousQueue 1.8 源码解析

ぐ巨炮叔叔 提交于 2020-03-23 16:16:20
[TOC] SynchronousQueue 1.8 源码解析 一,简介 SynchronousQueue 是一个很奇怪的队列,感觉都不能叫队列,因为内部没有数据的存储空间,队列不能peek,因为不存在元素,任何入队的线程都会阻塞,直到有线程来出队,也就是这个队列是一组操作,入队和出队要一起离开,出队也是一样,必须等入队,必须结伴而行;队列支持公平和非公平的模式(指的是队列匹配线程的顺序),公平模式的数据结构是队列(FIFO),非公平模式使用的是栈(LIFO)。 二,UML 图 三,基本成员 abstract static class Transferer<E> { // 出队入队都是这一个方法 abstract E transfer(E e, boolean timed, long nanos); } // npu数 static final int NCPUS = Runtime.getRuntime().availableProcessors(); // 带超时时间的自旋次数 static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32; // 没有超时的自旋次数 static final int maxUntimedSpins = maxTimedSpins * 16; TransferStack 非公平的实现,主要成员

Java多线程之线程协作

落花浮王杯 提交于 2020-03-23 15:56:44
常见的线程协作方式是:生产者/消费者。 一个线程作为生产者,生产要处理数据,比如拿一个线程来生产Order,用户每下一单,此线程就生产一个Order对象。 设置一个仓库,来存放生产出来的Order对象。 一个线程作为消费者,消费|处理仓库中的Order对象(打印订单、拣货、发货)。 demo 订单处理流程 1、用一个类来封装要处理的数据 public class Order { private int id; //... public Order(int id) { this.id = id; } public int getId() { return id; } //...... } 2、仓库 import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class OrderStorage { //使用阻塞队列作为仓库 private BlockingQueue<Order> queues; //默认仓库容量为50 public OrderStorage() { this.queues = new LinkedBlockingQueue<>(50); } //初始化仓库容量 public OrderStorage(int capacity) {

Async,Await和ConfigureAwait的关系

泪湿孤枕 提交于 2020-03-23 15:49:56
【转自】https://mp.weixin.qq.com/s/h10V-FshGoaQUWFPfy-azg 在.NET Framework 4.5中,async / await关键字已添加到该版本中,简化多线程操作,以使异步编程更易于使用。为了最大化利用资源而不挂起UI,你应该尽可能地尝试使用异步编程。虽然async / await让异步编程更简单,但是有一些你可能不知道的细节和注意的地方 新关键字 微软在.NET框架中添加了async和await关键字。但是,使用它们,方法的返回类型应为Task类型。(我们将在稍后讨论例外情况)为了使用await关键字,您必须在方法定义中使用async。如果你在方法定义中放入async,你应该在主体方法的某个地方至少有一处await关键字,如果你缺少他,你通常会收到Visual Studio的一个警告。 以下是代码中的示例: 1 public async Task ExecuteAsync(UpdateCarCommand request, CancellationToken token = default) 2 { 3 using (var context = _contextFactory.Create()) 4 { 5 var entity = context.Cars.FirstOrDefault(a => a.Id == request

C# BeginInvoke和EndInvoke方法

蹲街弑〆低调 提交于 2020-03-23 15:47:15
转载自: BeginInvoke和EndInvoke方法 IDE:Visual Studio 2008 本系列教程主要包括如下内容: 1. BeginInvoke和EndInvoke方法 2. Thread类 3. 线程池 4. 线程同步基础 5. 死锁 6. 线程同步的7种方法 7. 如何在线程中访问GUI组件 一、线程概述 在操作系统中一个进程至少要包含一个线程,然后,在某些时候需要在同一个进程中同时执行多项任务,或是为了提供程序的性能,将要执行的任务分解成多个子任务执行。这就需要在同一个进程中开启多个线程。我们使用C#编写一个应用程序(控制台或桌面程序都可以),然后运行这个程序,并打开windows任务管理器,这时我们就会看到这个应用程序中所含有的线程数,如下图所示。 如果任务管理器没有“线程数”列,可以【查看】>【选择列】来显示“线程计数”列。从上图可以看出,几乎所有的进程都拥有两个以上的线程。从而可以看出,线程是提供应用程序性能的重要手段之一,尤其在多核CPU的机器上尤为明显。 二、用委托(Delegate) 的BeginInvoke 和EndInvoke 方法操作线程 在C#中使用线程的方法很多,使用委托的BeginInvoke和EndInvoke方法就是其中之一。BeginInvoke方法可以使用线程异步地执行委托所指向的方法

Java 并发工具CountDownLatch和CyclicBarrier 原理解析

寵の児 提交于 2020-03-23 15:41:05
[TOC] Java 并发工具CountDownLatch和CyclicBarrier 原理解析 一,简介 CountDownLatch 允许一个或者多个线程等待其他线程完成操作。 CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程达到一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。 二,代码演示 CountDownLatchDemo public class CountDownLatchDemo { public static final CountDownLatch count = new CountDownLatch(10); private static int j = 0; public static void main(String[] args) throws Exception { for (int i = 0; i < 10; i++) { new Thread( ()-> { System.out.println("我是"+(++j)); count.countDown(); } ).start(); } count.await(); System.out.println("我是总数"+j+"!!!"); } } 运行结果: 我是1

ICE异步程序设计-----AMI/AMD

梦想的初衷 提交于 2020-03-23 15:38:19
1 简介 AMI 异步方法调用(AMI) 这个术语描述的是客户端的异步编程模型支持。 如果你使用AMI 发出远地调用,在Ice run time 等待答复的同时,发出调用的线程不会阻塞。相反,发出调用的线程可以继续进行各种活动,当答复最终到达时, Ice run time 会通知应用。通知是通过回调发给应用提供的编程语言对象的 AMD 一个服务器在同一时刻所能支持的同步请求数受到Ice run time 的服务器线程池的尺寸限制(参见15.3 节)。如果所有线程都在忙于分派长时间运行的操作,那么就没有线程可用于处理新的请求,客户就会经验到不可接受的无响应状态。异步方法分派(AMD) 是AMI 的服务器端等价物 ,能够解决这个可伸缩性问题 。 在使用AMD 时,服务器可以接收一个请求,然后挂起其处理,以尽快释放分派线程。当处理恢复、结果已得出时,服务器要使用Ice runtime 提供的回调对象,显式地发送响应。 使用AMD时,客户端如果需要等待返回值,那就一直等待,否则就继续往下执行。 为什么使用AMD? 用实际的术语说, AMD 操作通常会把请求数据(也就是,回调对象和操作参数)放入队列 ,供应用的某个线程(或线程池)随后处理用。这样,服务器就使分派线程的使用率降到了最低限度,能够高效地支持数千并发客户。 另外, AMD 还可用于需要在完成了客户的请求之后继续进行处理的操作

ConcurrentHashMap 源码浅析 1.7

落花浮王杯 提交于 2020-03-23 15:38:18
简介 (1) 背景 HashMap死循环:HashMap在并发执行put操作时会引起死循环,是因为多线程会导致HashMap的Entry链表形成环形数据结构,一旦形成环形数据结构,Entry的next节点永远不为空,就会产生死循环获取Entry. HashTable效率低下:HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下.因为当一个线程访问HashTable的同步方法,其它线程也访问HashTable的同步方法时,会进入阻塞或轮询状态.如线程1使用put进行元素添加,线程2不但不能使用put方法添加元素,也不能使用get方法获取元素,所以竞争越激烈效率越低. (2) 简介 HashTable容器在竞争激烈的并发环境下表现出效率低下的原因是所有访问HashTable的线程都必须竞争一把锁,假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么多线程访问容器里不同的数据段时,线程间不会存在竞争,从而可以有效提高并发访问效率,这就是ConcurrentHash所使用的锁分段技术.首先将数据分成一段一段地储存,然后给每一段配一把锁,当一个线程占用锁访问其中一段数据时,其它段的数据也能被其它线程访问. 结构 ConcurrentHashMap是由Segments数组结构和HashEntry数组结构组成

线程池

江枫思渺然 提交于 2020-03-23 15:35:08
线程池 [TOC] 线程池概述 什么是线程池 为什么使用线程池 线程池的优势 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。 第二:提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。 第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。但是要做到合理的利用线程池,必须对其原理了如指掌。 创建一个线程池并提交线程任务 线程池源码解析 参数认识 corePoolSize : 线程池的基本大小,当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。 runnableTaskQueue:任务对列,用于保存等待执行的任务的阻塞队列。可以选择以下几个阻塞队列。 ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。 LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue