Java-并发编程
军伟@
Java开发工程师
展开
-
Thread--基本概念
一、进程与线程的区别:进程是资源分配和运行调度的基本单位,一个进程可以看成是一个独立的程序,在内存中会有其对应的代码空间和数据空间,进程间需要通过消息通信来进行同步。每个进程都有自己的地址空间。线程是运行调度的基本单位,所有的线程共享器所属的进程的所有资源与代码,同时线程会拥有自己私有的堆栈。多线程则共享所在进程的地址空间。线程的状态图:线程包括5种状态:(1)新建状态(new):线程对象被创建之原创 2017-03-29 12:45:03 · 1118 阅读 · 3 评论 -
并发编程--Semaphore计数信号量
Semaphore是一个计数信号量,它的本质是一个共享锁。信号量维护了一个信号量许可集。线程可以通过调用acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。 线程可以通过release()来释放它所持有的信号量许可(用完信号量之后必须释放,不然其他线程可能会无法获取信号量)。简单示例:public class Semaphore原创 2017-04-19 19:37:40 · 2956 阅读 · 0 评论 -
并发编程--CyclicBarrier屏障
CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。简单示例:public class CyclicBarrierLearn { private static int SIZE = 5; private static Cy原创 2017-04-18 19:55:01 · 901 阅读 · 0 评论 -
并发编程--CountDownLatch
CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDown原创 2017-04-18 18:49:35 · 1829 阅读 · 0 评论 -
并发编程--AtomicIntegerArray、AtomicLongArray和AtomicReferenceArray
AtomicIntegerArray、AtomicLongArray和AtomicReferenceArray是对数组的线程安全操作,简单来说其操作方式是使用sun.misc.Unsafe来对数组对象进行CAS原子操作。AtomicIntegerArray数组对象: private final int[] array;添加操作为: public final void set(int i, int原创 2017-04-05 19:13:17 · 1955 阅读 · 0 评论 -
并发编程--并发编程包Condition条件
JDK并发编程包提供了Condition来对锁进行更精确的控制,Condition接口提供的方法还是很简单的,Condition是一个独占锁。Condition是一个多线程间协调通信的工具类,使得某个,或者某些线程一起等待某个条件(Condition),只有当该条件具备( signal 或者 signalAll方法被带调用)时 ,这些等待线程才会被唤醒,从而重新争夺锁。Condition接口方法:原创 2017-04-18 18:18:50 · 1272 阅读 · 0 评论 -
并发编程--原子类AtomicLong、AtomicBoolean和AtomicReference
在上一篇博客 并发编程--原子类AotmicInteger中我们已经简单介绍了一下AtomicInteger相关的知识,简单来说AtomicLong的实现原理与AtomicInteger是相同的,用volatile来修饰变量value和使用sun.misc.Unsafe来完成对value的原子操作。源码如下:public class AtomicLong extends Number implem原创 2017-04-05 18:12:39 · 1717 阅读 · 0 评论 -
并发编程--原子类AotmicInteger
前几篇博客中我们已经介绍了线程、volatile、synchronized和cas自旋相关的知识,接下来我介绍一下jdk提供的并发编程包java.util.concurrent中相关的实现类知识。 AtomicInteger简单来说就是一个能进行原子操作的Integer,这样在多线程操作下对AtomicInteger的操作是原子操作的,操作后的值对所有线程都是立即可见的。简单来说其实现就是使用的v原创 2017-04-05 18:11:46 · 1797 阅读 · 0 评论 -
并发编程--读写锁ReadWriteLock和ReentrantReadWriteLock(一)
Java并发编程包提供了读写锁的实现,其维护了一对相关的锁 — — “读取锁”和“写入锁”,一个用于读取操作,另一个用于写入操作。“读取锁”用于只读操作,它是“共享锁”,能同时被多个线程获取。“写入锁”用于写入操作,它是“独占锁”,写入锁只能被一个线程锁获取。ReadWriteLock是一个接口。ReentrantReadWriteLock是它的实现类,ReentrantReadWriteLock原创 2017-04-25 20:18:15 · 1795 阅读 · 0 评论 -
并发编程--线程池Executor(一)
合理利用线程池能够带来三个好处。第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。但是要做到合理的利用线程池,必须对其原理了如指掌。线程池的架构图如下:1.转载 2017-07-25 19:47:22 · 1243 阅读 · 0 评论 -
Java集合--CopyOnWriteArraySet
它是线程安全的无序的集合,可以将它理解成线程安全的HashSet。有意思的是,CopyOnWriteArraySet和HashSet虽然都继承于共同的父类AbstractSet;但是,HashSet是通过“散列表(HashMap)”实现的,而CopyOnWriteArraySet则是通过“动态数组(CopyOnWriteArrayList)”实现的,并不是散列表。和CopyOnWriteArr...原创 2017-07-20 23:00:16 · 1349 阅读 · 0 评论 -
Java集合--CopyOnWriteArrayList
CopyOnWriteArrayList相当于线程安全的ArrayList。和ArrayList一样,它是个可变数组;但是和ArrayList不同的时,它具有以下特性:1. 它最适合于具有以下特征的应用程序:List 大小通常保持很小,只读操作远多于可变操作,需要在遍历期间防止线程间的冲突。2. 它是线程安全的。3. 因为通常需要复制整个基础数组,所以可变操作(add()、set() 和 r...原创 2017-07-19 14:25:19 · 766 阅读 · 0 评论 -
Java中CAS详解
在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁锁机制存在以下问题:(1)在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。(2)一个线程持有锁会导致其它所有需要此锁的线程挂起。(3)如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险。volatile是不错的机制,但是volatile不能保证原子性。因...转载 2018-05-19 12:25:59 · 703 阅读 · 0 评论 -
Java 多线程:InheritableThreadLocal 实现原理
前言介绍 InheritableThreadLocal 之前,假设对 ThreadLocal 已经有了一定的理解,比如基本概念,原理,如果没有,可以参考:Java 多线程:threadlocal关键字。这里再复习下 ThreadLocal 的原理,因为会对 InheritableThreadLocal 的理解 有重大的帮助:每个线程都有一个 ThreadLocalMap 类型的 threadLoc...转载 2018-05-11 11:40:00 · 1037 阅读 · 0 评论 -
Java内存模型
Java内存模型即Java Memory Model,简称JMM。JMM定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式。JVM是整个计算机虚拟模型,所以JMM是隶属于JVM的。如果我们要想深入了解Java并发编程,就要先理解好Java内存模型。Java内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共享变量进行同步。原始的Java内存模型效率并不是很理想,因此Ja...转载 2018-04-15 11:08:55 · 568 阅读 · 0 评论 -
并发编程--读写锁ReadWriteLock和ReentrantReadWriteLock写锁与读锁(二)
在上一篇博客并发编程--读写锁ReadWriteLock和ReentrantReadWriteLock(一)中我们简单介绍了一下读写锁的相关知识,接下来来我们介绍一下读锁的实现机制,简单的来说写锁就是一个独占锁,如果看过ReentrantLock相关的知识,应该会对独占锁的实现有一些简单的理解,简单来说独占锁的实现是当锁标识位state为0时,当前线程获取锁,并将state进行加一操作,其他线程来原创 2017-04-25 20:18:47 · 1571 阅读 · 0 评论 -
并发编程--线程池拒绝策略RejectedExecutionHandler(三)
线程池的拒绝策略,是指当任务添加到线程池中被拒绝,而采取的处理措施。当任务添加到线程池中之所以被拒绝,可能是由于:第一,线程池异常关闭。第二,任务数量超过线程池的最大限制。线程池共包括4种拒绝策略,它们分别是:AbortPolicy, CallerRunsPolicy, DiscardOldestPolicy和DiscardPolicy。ThreadPoolExecutor默认的拒绝策略是Abor原创 2017-07-27 21:48:36 · 7609 阅读 · 0 评论 -
并发编程--线程池ThreadPoolExecutor实现原理(二)
ThreadPoolExecutor是线程池类。对于线程池,可以通俗的将它理解为"存放一定数量线程的一个线程集合。线程池允许若个线程同时允许,允许同时运行的线程数量就是线程池的容量;当添加的到线程池中的线程超过它的容量时,会有一部分线程阻塞等待。线程池会通过相应的调度策略和拒绝策略,对添加到线程池中的线程进行管理。"1. workersworkers是HashSet类型,即它是一个Worker集合原创 2017-07-26 19:55:01 · 1152 阅读 · 0 评论 -
并发编程--并发编程包LockSupport
LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。LockSupport主要提供了两个功能:(1)park()方法,用来阻塞线程。(2)unpark()方法,解除阻塞线程。LockSupport提供的park()和unpark()方法不会遇到Thread.suspend和Thread.resume所可能引起的死锁问题,因为park和unpark有许可的存在,调用park的线程和另一原创 2017-04-18 12:53:25 · 1093 阅读 · 0 评论 -
并发编程--公平锁和非公平锁
在上一篇博客并发编程--互斥锁ReentrantLock中我们简单介绍了一下ReentrantLock,ReentrantLock提供了公平锁和非公平锁的机制,我们已经了解到ReentrantLock提供了一个FIFO线程队列,对于公平锁来说,当锁是可获取时首先让FIFO队列中的线程获取锁,当前线程需要进FIFO队列进行等待;对于非公平锁来说,当锁是可获取时,这个线程可以直接获取锁,不用在FIFO原创 2017-04-13 21:15:17 · 1526 阅读 · 0 评论 -
Thread--线程让步yield
yield()函数的作用是让步,它让当前线程由运行状态进入就绪状态,而不是像wait()一样进入阻塞状态。因此,并不能保证在当前线程调用yield()之后,其他具有相同优先级的线程一定能获得执行权,也有可能是当前线程又重新进入了运行状态。示例代码:class ThreadA extends Thread{ public ThreadA(String name){ supe原创 2017-03-29 17:16:55 · 869 阅读 · 0 评论 -
Java-线程Thread等待与唤醒
Java线程的等待与唤醒主要包括几个方法:(1)notify():唤醒在此对象监视器上等待的单个线程。(2)notifyAll():唤醒在此对象监视器上等待的所有线程。(3)wait():让当前线程处于阻塞状态,同时释放它所持有的锁。(4)wait(long timeout):让线程处于阻塞状态,直到其他线程调用此对象的notify()或者notifyAll()方法,或者超过指定的时间量,当前线程原创 2017-03-29 17:13:37 · 5216 阅读 · 0 评论 -
Java-线程Thread方法start()和run()
(1)start():作用是启动一个新的线程,新线程会执行线程中相应的run()方法,start()不能被重复调用,(2)run():该方法和普通的成员方法一样,可以被重复调用。如果直接调用run()的话,会在当前线程中执行run(),而并不会启动新的线程。示例代码:public class NewThread extends Thread{ public NewThread(Stri原创 2017-03-29 17:09:42 · 925 阅读 · 0 评论 -
Thread--Thread和Runnable
在Java中常用的实现多线程的两种方式是使用Thread类或者实现Runnable接口。Runnable是一个接口,并且只包含了一个run()方法。基于Java8的Runnable源码:@FunctionalInterfacepublic interface Runnable {/** * When an object implementing interface Runnable原创 2017-03-29 12:48:37 · 806 阅读 · 0 评论 -
Thread--线程休眠sleep
sleep()的作用是让当前线程进入休眠,当前线程会由运行状态进入到阻塞状态,sleep()可以指定休眠时间,休眠时间会大于等于该休眠时间,在线程被重新唤醒时,线程的状态由阻塞状态变成就绪状态,从而等待CPU进行调度执行。示例代码:class ThreadA extends Thread{ public ThreadA(String name){ super(name);原创 2017-03-29 17:18:20 · 5881 阅读 · 0 评论 -
Thread--Join方法
join()函数是Thread类中定义的一个方法,join()的作用是让主线程等待子线程结束之后才能继续进行,简单的示例说明:// 主线程public class Father extends Thread { public void run() { Son s = new Son(); s.start(); s.join();原创 2017-03-29 17:20:14 · 904 阅读 · 0 评论 -
并发编程--互斥锁ReentrantLock
ReentrantLock是一个比较常用的锁,它是一个互斥锁,互斥锁的含义就是只能由某个线程进行操作,其他线程等到释放锁资源之后才能竞争锁;同时它又是可重入的,意思是它可以被单个线程多次获取。ReentrantLock可以获取公平锁和非公平锁,其区别的体现是获取锁的机制上是否公平,ReentrantLock在同一个时间点只能被一个线程获取(当某线程获取到“锁”时,其它线程就必须等待);Reentr原创 2017-04-13 19:55:34 · 899 阅读 · 0 评论 -
并发编程--并发编程框架概述
JDK给我们提供了一个并发编程的包java.util.current,并发编程包中是锁功能更加强大,并且他允许更灵活的使用锁。JUC包中的锁,包括:Lock接口,ReadWriteLock接口,LockSupport阻塞原语,Condition条件,AbstractOwnableSynchronizer/AbstractQueuedSynchronizer/AbstractQueuedLongSy原创 2017-04-13 18:25:06 · 1042 阅读 · 0 评论 -
并发编程--AbstractQueuedSynchronizer介绍和原理分析
AbstractQueuedSynchronizer是并发编程包中最重要的类,是并发编程包的实现基层。简单来说,AbstractQueuedSynchronizer提供了一个基于FIFO的队列,用于存储处于阻塞状态的线程;提供了一个volatile修改的state变量,用于作为锁获取的标识位,对于FIFO队列和state的操作都是通过Unsafe这个类来实现CAS原子操作。 AQS的功能可以分为两原创 2017-04-17 21:09:19 · 2252 阅读 · 2 评论 -
并发编程--CAS自旋锁
在前两篇博客中我们介绍了并发编程--volatile应用与原理和并发编程--synchronized的实现原理(二),接下来我们介绍一下CAS自旋锁相关的知识。一、自旋锁提出的背景由于在多处理器系统环境中有些资源因为其有限性,有时需要互斥访问(mutual exclusion),这时会引入锁的机制,只有获取了锁的进程才能获取资源访问。即是每次只能有且只有一个进程能获取锁,才能进入自己的临界区,同一原创 2017-03-31 20:53:11 · 6653 阅读 · 0 评论 -
并发编程--volatile应用与原理
volatile在并发编程中扮演着重要的角色(并发编程包java.util.concurrent中运用了volatile的特性),volatile被称为轻量级锁,它在多处理器开发中保证了共享变量的“可见性”,可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下原创 2017-03-30 20:05:33 · 987 阅读 · 0 评论 -
并发编程--synchronized示例(一)
在Java中,每一个对象有且仅有一个同步锁,同步锁是依赖于对象而存在。当调用某个对象的synchronized方法时,就获取了该对象的同步锁。不同线程对同步锁的访问时互斥的。synchronized基本规则:(一)当一个线程访问某个对象的synchronized方法或者代码块时,其他线程对此对象的synchronized方法或者代码块的访问都会被阻塞。(二)当一个线程访问某个对象的synchron原创 2017-03-29 19:12:34 · 911 阅读 · 0 评论 -
并发编程--synchronized的实现原理(二)
上一篇博客Thread--synchronized示例(一)中我们简单介绍了一下有关synchronized相关的知识,接下来我们详细介绍一下synchronized的实现原理。在多线程并发编程中synchronized一直是元老级角色,很多人都会称呼它为重量级锁,随着对其的实现的各种优化,在有些情况下他就并不那么重了,为了减少获取锁和释放锁带来的性能消耗而引入了偏向锁和轻量级锁,以及对锁的存储结原创 2017-03-30 19:36:02 · 1384 阅读 · 0 评论 -
Thread--interrupt和线程终止
interrupt()的作用是中断本线程,本线程中断自己是被允许的,其他线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限,可能会抛出SecurityException异常。一、终止处于“阻塞状态”的线程:通过中断方式终止处于阻塞状态的线程,当线程由于被调用了sleep(),wait(),join()等方法而进入阻塞状态,此时调用线程的interrupt()将线原创 2017-03-29 17:24:43 · 1121 阅读 · 0 评论 -
Java集合--ArrayBlockingQueue
ArrayBlockingQueue是数组实现的线程安全的有界的阻塞队列。线程安全是指,ArrayBlockingQueue内部通过“互斥锁”保护竞争资源,实现了多线程对竞争资源的互斥访问。而有界,则是指ArrayBlockingQueue对应的数组是有界限的。 阻塞队列,是指多线程访问竞争资源时,当竞争资源已被某线程获取时,其它要获取该资源的线程需要阻塞等待;而且,ArrayBlockingQ...原创 2017-07-24 22:38:44 · 993 阅读 · 0 评论