Java本身自带了很多支持多线程的容器。

Java自带的Vector容器本身就是同步容器,所有相关操作是原子操作。但是不能总是解决问题,因为有时候判断和操作分离,虽然操作是原子性的,但是判断和操作一起酒不是了。

Java自带的HashMap也是同步容器,但是效率不如Java自带并发容器,比如ConcurrentHashMap。

并发性要求高用ConcurrentHashMap,如果同时要求排序可以使用ConcurrentSkipList。如果并发度要求不高,可以使用hashtable或者hashmap。


CopyOnWriteArrayList容器也是一种支持高并发的容器,用在写操作少但是读操作很多的场景。其本质是将读写分离。当在CopyOnWriteArrayList里处理写操作[add、remove、set等]是先将原始的数据通过Arrays.copyof()来生成一份新的数组,然后在新的数据对象上进行写,写完后再将原来的引用指向到当前这个数据对象,这样保证了每次写都是在新的对象上[因为要保证写的一致性,这里要对各种写操作要加一把锁]。读的时候就是在引用的当前对象上进行读[包括get,iterator等],不存在加锁和阻塞。

CopyOnWriteArrayList中写操作需要大面积复制数组,所以性能肯定很差,但是读操作因为操作的对象和写操作不是同一个对象,读之 间也不需要加锁,读和写之间的同步处理只是在写完后通过一个简单的“=”将引用指向新的数组对象上来,这个几乎不需要时间,这样读操作就很快很安全,适合 在多线程里使用,绝对不会发生ConcurrentModificationException ,所以最后得出结论:CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。


ConcurrentLinkedQueue也是常用的容器。常用操作offer,poll,peek都是同步操作。

另一种并发模式下常用的容器是BlockingQueue,这是一种阻塞机制的队列。满足或者不满足一定条件的时候,线程就会自动等待[阻塞后续操作]知道条件不满足或者满足,才会继续执行。常用的BlockingQueue包括LinkedBlockingQueue,ArrayBlockingQueue,TransferQueue,SynchronusQueue等等。

DelayQueue是队列中每个元素需要等待一段时间才可以出队列。


线程池是一种广泛使用的支持并发操作的线程管理技术。

java.util.concurrent.Executor是Java线程池实现的顶级接口,非常简单,只有一个execute方法需要实现。也就是允许开发者自己定义如何进行业务逻辑。

java.util.concurrent.ExecutorService接口继承自Executor接口。除了父接口的execute方法,还定义了很多其他的方法。

java.util.concurrent.Executors是一个操作Executor的工具类。内部有大量的静态方法,可以不经实例化就直接调用。比如可以通过Executors.newFixedThreadPool()创建一个线程池。

Runnable和Callable接口方别调用run方法和call方法。

CachedThreadPool在开始状态在没有线程,此时来了第一个任务就创建新一个线程来处理,此时来了第二个任务,如果之前的线程已经完成了第一个人物则它急需处理第二个人物,否则再创建一个新线程处理第二个任务,如此往复,直到到达系统内存可以支持的最大线程数为止。已经创建的线程如果idle超过一定时间,就会被销毁。所以相对于newFiexedThreadPool,CachedThreadPool是一种灵活的线程。

newSingleThreadExecutor可以实现单例模式,每次都返回相同的线程。

newWorkStealingPool实现的线程池在空闲的时候,会自动寻找可以执行的job,也就是steal job过来执行。具体启动线程数量等于CPU核数。本质上是通过ForkJoinPool来实现的。

ForkJoinPool是一个比较复杂的线程。Fork是分叉,Join是合并,所以ForkJoinPool用于一个大任务切分成多个小任务,这些小任务如果还大,可以再次切分。[ForkJoinPool是JDK1.7之后才有的]

除了ForkJoinPool之外,其他的ThreadPool,底层实现都是ThreadPoolExecutor这个类,只不过参数不同,BlockingQueue的实现不一样而已。所以ThreadPoolExecutor允许用户自定义一个新的线程池。


Future是线程在未来的某一个时间点执行并返回的结果。FutureTask是和RunnableTask对应。FutureTask内部包装了Callable方法,而该方法有一个泛型T的返回值,所以FutureTask也有返回值

public class MyFuture {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		FutureTask<Integer> task = new FutureTask<>(()->{
			TimeUnit.MILLISECONDS.sleep(500);
			return 1000;
		});
		new Thread(task).start();
		System.out.println(task.get());
		
		ExecutorService service = Executors.newFixedThreadPool(5);
		Future<Integer> future = service.submit(()->{
			TimeUnit.MILLISECONDS.sleep(500);
			return 1;
		});
		
		System.out.println(future.isDone());
		System.out.println(future.get());
		System.out.println(future.isDone());
	}
}