并发

JAVA与并发

空扰寡人 提交于 2021-01-19 03:54:16
API 在java1.5之前,java的并发API都是依靠Thread, Runnable, ThreadLocal, ThreadGroup以及Object特有的现成先关方法所构成。此外,还有synchronized, volatile两个关键字对同步和内存一致性的定义。从1.5开始,java的API中多了一个包, java.util.concurrent, 更丰富了并发的API。 本文不是普及知识,所以不对每个API都做详尽的解释,但还是有必要列一张简单的表格。 同步机制 API Java版本 描述 示例 synchronized(obj) { } 1.4 多线程在此代码块必须同步执行 。 线程的interrupt()方法对同步锁上的阻塞是无效的,当线程获取到锁而进入同步块后, 可以调用Thread.interrupted()方法来检验本线程是否被interrupted了。 synchronized(obj) { if (Thread.interrupted()) { // This thread is interrupted. } } Lock since 1.5 替换synchronized。 Lock l = new ReentrantLock(); l.lock(); try { // access the resource protected by this lock

Condition.await, signal 与 Object.wait, notify 的区别

半城伤御伤魂 提交于 2020-12-31 12:01:27
Object 类中 wait,notify 与 notifyAll 方法可以用来实现线程之间的调度,比如在阻塞队列(BlockingQueue)的实现中,如果队列为空,则所有消费者线程进行阻塞 ( wait ),如果某一个时刻队列中新添加了一个元素,则需要唤醒某个或所有阻塞状态的消费者线程( notify,notifyAll ),同理如果是队列已满,则所有生产者线程都需要阻塞,等到某个元素被消费之后又需要唤醒某个或所有正在阻塞的生产者线程 Condition 的 await,signal, singalAll 与 Object 的 wait, notify, notifyAll 都可以实现的需求,两者在使用上也是非常类似,都需要先获取某个锁之后才能调用,而不同的是 Object wait,notify 对应的是 synchronized 方式的锁,Condition await,singal 则对应的是 ReentrantLock (实现 Lock 接口的锁对象)对应的锁 来看下面具体的示例:使用 wait, notify 和 await, signal 方式分别实现一个简单的队列 public interface SimpleQueueDemo<E> { void put(E e); E take(); } 基于 Object wait, notify 的实现 public

用Golang处理每分钟100万份请求

廉价感情. 提交于 2020-11-01 18:56:22
我在几家不同的公司从事反垃圾邮件,防病毒和反恶意软件行业工作超过15年,现在我知道这些系统最终会因为我们每天处理的大量数据而变得复杂。 目前,我是smsjunk.com的CEO和KnowBe4的首席架构师,他们都是网络安全行业的公司。 有趣的是,在过去的10年左右,作为一名软件工程师,我参与过的所有Web后端开发大部分都是在Ruby on Rails中完成的。不要误会我的意思,我喜欢Ruby on Rails,我相信这是一个了不起的环境,但是过了一段时间,你开始用ruby的方式思考和设计系统,而且如果你忘记了软件架构的效率和简单性-可以利用多线程,并行化,快速执行和小内存开销。多年来,我是一名C / C ++,Delphi和C#开发人员,而且我刚开始意识到使用正确的工具进行工作可能会有多复杂。 我对互联网总是争论的语言和框架战争并不太感兴趣。 我相信效率,生产力和代码可维护性主要取决于您构建解决方案的简单程度。 问题 在处理我们的匿名遥测和分析系统时,我们的目标是能够处理来自数百万端点的大量POST请求。Web处理程序将收到一个JSON文档,该文档可能包含需要写入Amazon S3的多个有效内容的集合,以便我们的map-reduce系统稍后对这些数据进行操作。 传统上,我们会考虑创建一个工作层架构,利用诸如以下方面的内容: Sidekiq Resque DelayedJob

Volatile关键字能保证操作的原子性吗

最后都变了- 提交于 2020-10-28 09:14:37
1.volatile关键字的两层语义   一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:   1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。   2)禁止进行指令重排序。 先看一段代码,假如线程1先执行,线程2后执行: //线程1 boolean stop = false; while(!stop){ doSomething(); } //线程2 stop = true; 这段代码是很典型的一段代码,很多人在中断线程时可能都会采用这种标记办法。但是事实上,这段代码会完全运行正确么?即一定会将线程中断么?不一定,也许在大多数时候,这个代码能够把线程中断,但是也有可能会导致无法中断线程(虽然这个可能性很小,但是只要一旦发生这种情况就会造成死循环了)。   下面解释一下这段代码为何有可能导致无法中断线程。在前面已经解释过,每个线程在运行过程中都有自己的工作内存,那么线程1在运行的时候,会将stop变量的值拷贝一份放在自己的工作内存当中。   那么当线程2更改了stop变量的值之后,但是还没来得及写入主存当中,线程2转去做其他事情了,那么线程1由于不知道线程2对stop变量的更改,因此还会一直循环下去。   但是用volatile修饰之后就变得不一样了:   第一

current包下ReentrantReadWriteLock的使用

与世无争的帅哥 提交于 2020-04-12 14:02:47
ReentrantReadWriteLock中可以生产读锁和写锁。 读锁和读锁不互斥,写锁和任何读锁或者写锁都互斥。 demo:读锁和读锁不互斥 public static void main(String[] args) { ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); final ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock(); final ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock(); for (int i = 0; i < 5; i++) { new Thread(new Runnable() { public void run() { try { readLock.lock(); System.out.println(Thread.currentThread().getName() + " 开始读取数据"); TimeUnit.SECONDS.sleep(5); System.out.println(Thread.currentThread()

如何提高Java并行程序性能

筅森魡賤 提交于 2020-03-25 12:29:49
3 月,跳不动了?>>> 在Java程序中,多线程几乎已经无处不在。与单线程相比,多线程程序的设计和实现略微困难,但通过多线程,我们却可以获得多核CPU带来的性能飞跃,从这个角度说,多线程是一种值得尝试的技术。那么如何写出高效的多线程程序呢? 1、有关多线程的误区:线程越多,性能越好 不少初学者可能认为,线程数量越多,那么性能应该越好。因为程序给我们的直观感受总是这样。一个两个线程可能跑的很难,线程一多可能就快了。但事实并非如此。因为一个物理CPU一次只能执行一个线程,多个线程则意味着必须进行线程的上下文切换,而这个代价是很高的。因此,线程数量必须适量,最好的情况应该是N个CPU使用N个线程,并且让每个CPU的占有率都达到100%,这种情况下,系统的吞吐量才发挥到极致。但现实中,不太可能让单线程独占CPU达到100%,一个普遍的愿意是因为IO操作,无论是磁盘IO还是网络IO都是很慢的。线程在执行中会等待,因此效率就下来了。这也就是为什么在一个物理核上执行多个线程会感觉效率高了,对于程序调度来说,一个线程等待时,也正是其它线程执行的大好机会,因此,CPU资源得到了充分的利用。 2、尽可能不要挂起线程 多线程程序免不了要同步,最直接的方法就是使用锁。每次只允许一个线程进入临界区,让其它相关线程等待。等待有2种,一种是直接使用操作系统指令挂起线程,另外一种是自旋等待。在操作系统直接挂起

自旋锁学习系列(3):指数后退技术

可紊 提交于 2020-03-23 21:48:51
3 月,跳不动了?>>> 上一篇 中分析了测试锁的两种实现TASLock和TTASLock,主要对这两种锁的性能进行了分析。对于TTASLock,我们知道比TASLock性能上要好很多,具体分析已经讲过了。我们最后也说了,TTASLock虽然比TASLock大有改进,但是在性能上还是不够理想。这一篇的目的就是针对TTASLock做一下改进。 我们再来看一下TTASLock的实现源码和加锁的流程图: /** * * Test test and set lock * */ public class TTASLock { private AtomicBoolean state = new AtomicBoolean(false); // 加锁 public void lock() { while (true) { while (state.get()) { // 自旋 } if (!state.getAndSet(true)) { break; } } } // 解锁 public void unlock() { state.set(false); } } 加锁流程图如下: 从上文我们知道,对于TTASLock锁,性能问题主要出现在解锁上。一旦一个已经获得锁的线程执行解锁操作。其他线程都会产生缓存缺失,将会由”本地自旋”转变为从共享服务器中去获取状态值。这会消耗大量的总线资源。所以

自旋锁学习系列(2):TAS锁

为君一笑 提交于 2020-03-23 21:00:26
3 月,跳不动了?>>> TAS 是test and set 的缩写,直白的翻译过来就是比较然后测试。java中的原子类大量使用了TAS操作。通过TAS 我们可以安全并且无阻塞的设置原子变量,不用加锁也能进行线程安全的操作。本文目的不是谈原子变量的使用和实现原理的,这个以后会单独来讲。我们主要来看如何使用TAS操作来实现互斥锁。 首先让我们来看看最简单的一种实现TASLock,废话少说直接上代码: //test and set lock public class TASLock { private AtomicBoolean state = new AtomicBoolean(false); // 加锁 public void lock() { while (state.getAndSet(true)) { } } // 解锁 public void unlock() { state.set(false); } } 这应该是互斥锁的最简单的实现了吧,加锁和解锁只需要一行有效代码。让我们详细来分析一下TASLock类。TASLock有一个AtomicBoolean类型的字段state,我们用这个字段来标示锁的状态,初始值为false。state为true说明锁已经被某个线程占有,fase则说明锁空闲。AtomicBoolean是布尔值的一个原子类型实现类

进程与线程的概念

不想你离开。 提交于 2020-03-20 23:49:21
3 月,跳不动了?>>> 1.并行和并发 并行性是指两个或多个时间在同一时刻发生,而并发性是指两个或多个事件在同一时间间隔内发生 。在多道程序环境下,并发性是指在一段时间内宏观有多个程序在同时运行,但在单处理机系统中每一时刻却仅能有一道程序执行,故微观上这些程序只能是分时地交替执行。倘若在计算机系统中有多个处理机,则这些可以并发执行的程序便可分配到多个处理机上,实现并行执行,即利用每个处理机来处理一个可并发执行的程序,这样,多个程序便可同时执行。 2.进程 通常的程序是静态实体(PassiveEntity),在多道程序系统中,它们是不能独立运行的,更不能和其它程序并发执行。 在操作系统中引入进程的目的,就是为了使多个程序能并发执行。例如,在一个未引入进程的系统中,在属于同一个应用程序的计算程序和I/O程序之间,两者只能是顺序执行,即只有在计算程序执行告一段落后,才允许I/O程序执行;反之,在程序执行I/O操作时,计算程序也不能执行,这意味着处理机处于空闲状态。但在引入进程后,若分别为计算程序和I/O程序各建立一个进程,则这两个进程便可并发执行。 由于在系统中具备使计算程序和I/O程序同事运行的硬件条件,因而可将系统中的CPU和设备同时开动起来,实现并行工作 ,从而有效提高资源的利用率和系统吞吐量,并改善系统的性能。 事实上可以在内存中存放多个用户程序,分别为他们建立进程后

进程,线程,超线程,并发,并行 等概念

我的梦境 提交于 2020-03-20 23:43:57
3 月,跳不动了?>>> 进程是操作系统对一个正在运行的程序的抽象,即操作系统为该进程虚拟了独自的处理器资源,内存空间(又称虚拟地址空间)与磁盘空间 线程是进程中多个可以派遣的工作单位(或称执行单元,以CPU的角度来看)的集合,同一进程的多个线程共享该线程的资源(包括运行时在虚拟地址空间加载的代码,全局数据等) 并发(concurrency)从最终用户的角度来看,就是同时运行多个本地应用程序(或者网络应用程序例如 web服务器 同时处理来自多个远程用户的页面请求 / 活动连接 的过程) 并发 从计算机底层实现原理来看,是CPU等硬件 在操作系统所抽象出来的多个进程(或线程)之间快速来回切换执行的过程;具体讲,某一极短时间间隔内,CPU只能执行一个进程(或线程) 超线程(hyper threading,HT)也称“同时多线程”(simultaneous multi-threading) 采用超线程技术的多核CPU的任意一个物理核心在某一极短时间间隔内可以“同时”执行两个或多个线程 例如传统的单线程CPU,在某一极短时间间隔内只能执行一个线程,单线程CPU在不同线程间切换需要20,000个时钟周期 超线程多核CPU的任意一个物理核心在不同线程间切换只需要一个时钟周期; 典型的例子是 Intel Core i7 四核心处理器,一个物理核心可以同时执行两个线程, 总共可以“并行