JDK7提供了一个将任务“分而治之”的框架 — Fork/Join。它把一个大的任务分割成足够小的子任务,如果子任务比较大的话还要对子任务进行继续分割。分割的子任务分别放到双端队列里,然后启动线程分别从双端队列里获取任务执行。子任务执行完的结果都放在另外一个队列里,启动一个线程从队列里取数据,然后合并这些数据。
深入学习Java线程池
在前面的例子中,我们都是通过new Thread
来创建一个线程,由于线程的创建和销毁都需要消耗一定的CPU资源,所以在高并发下这种创建线程的方式将严重影响代码执行效率。而线程池的作用就是让一个线程执行结束后不马上销毁,继续执行新的任务,这样就节省了不断创建线程和销毁线程的开销。
集合线程安全问题
常用的集合类型如ArrayList,HashMap,HashSet等,在并发环境下修改操作都是线程不安全的,会抛出java.util.ConcurrentModificationException
异常,这节主要记录如何在并发环境下安全地修改集合数据。
Java Concurrency Lock
Lock锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源(但是有些锁可以允许多个线程并发的访问共享资源,比如读写锁)。在Lock接口出现之前,Java程序是靠synchronized关键字实现锁功能的,而Java SE 5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。虽然它缺少了(通过synchronized块或者方法所提供的)隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性。
ThreadLocal使用学习
ThreadLocal字面上的意思是局部线程变量,每个线程通过ThreadLocal的get
和set
方法来访问和修改线程自己独有的变量。简单地说,ThreadLocal的作用就是为每一个线程提供了一个独立的变量副本,每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
深入学习CAS
在深入理解volatile关键字一节中,我们提到volatile并不能确保线程安全性,要解决文章中提到的累加例子线程安全问题的话,可以使用同步锁(synchronized)和Atomic类型。但就那个例子来说,使用synchronized同步锁有点小题大作,我们可以选择更为轻量的AtomicInteger来解决。
JUC之Semaphore
JUC的Semaphore俗称信号量,可用来控制同时访问特定资源的线程数量。通过它的构造函数我们可以指定信号量(称为许可证permits可能更为明确)的数量,线程可以调用Semaphore对象的acquire
方法获取一个许可证,调用release
来归还一个许可证。
下面举个Semaphore的基本使用示例。
深入理解volatile关键字
volatile关键字修饰的成员变量具有两大特性:保证了该成员变量在不同线程之间的可见性;禁止对该成员变量进行重排序,也就保证了其有序性。但是volatile修饰的成员变量并不具有原子性,在并发下对它的修改是线程不安全的。下面分别举例来演示这两个特性,并且分析为什么volatile不是线程安全的。