CopyOnWriteArrayList
When
CopyOnWriteArrayList是jdk1.5以后并发包提供的一种并发容器,写操作通过创建底层的数组的新副本实现,是一种读写分离的并发策略,被我们称为“写时复制容器”,类似的还有CopyOnWriteArraySet
Way
集合框架ArrayList是线程不安全的,vector虽然是线程安全的,但处理方式简单粗暴synchronized,性能差,而CopyOnWriteArrayList提供了不同的的处理并发思路
How
很多时候,我们的系统中处理的都是读多写少的并发场景,CopyOnWriteArrayList允许并发的读,读操作是无锁的,性能比较高,写操作的话,比如向容器内增加一个元素,首先将当前容器复制一份,然后在新副本进行操作,结束之后将原容器的引用接向新容器
优缺点分析
优点:
读操作性能很高,因为无需同步操作,比较适合读多写少的并发情况
缺点:
一是内存占用问题,因为写操作都要复制
二是无法保证实时性,在写操作的时候,读操作是不会发生阻塞的,未切换到新容器,读操作无法读到最新的内容
Callable
Callable和Runable都代表着任务,区别于Runable在与有返回值并且可以抛异常
Callable的call()方法类似Runable中的run方法,都定义要完成的工作,实现这两个接口时分别要重写这2个方法,主要的不同之处在call()有返回值,运行callable任务可以拿到一个future对象,表示异步计算的结果,它提供检测计算是否完成的方法,以等待计算的完成,并检索计算的结果,通过Future对象可以了解任务执行的情况,可取消任务的执行,还可以获取执行的结果
Callable类型的任务可以有两种执行方式
借助FutureTask
package com.boom.example.demo.aa;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
public class CallableAndFutureTask {
public static void main(String[] args) {
Callable<Integer> objectCallable = new Callable<>(){
@Override
public Integer call() throws Exception {
return new Random().nextInt(100);
}
};
FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(objectCallable);
new Thread(integerFutureTask).start();
try {
Thread.sleep(5000);
System.out.println(integerFutureTask.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Callable任务和线程池一起使用,然后返回值是Future:
package com.boom.example.demo.aa;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableAndFuture {
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Integer> submit = executorService.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return new Random().nextInt(10);
}
});
Thread.sleep(5000);
System.out.println(submit.get());
executorService.shutdown();
}
}
当执行多个Callable任务,有多个返回值时,我们可以创建一个Future的集合,例如:
package com.boom.example.demo.aa;
import java.util.ArrayList;
import java.util.concurrent.*;
class MyCallableTask implements Callable<String>{
private int id;
public MyCallableTask(int id) {
this.id = id;
}
@Override
public String call() throws Exception {
for(int i = 1;i<=5;i++){
System.out.println("Thead" + id);
}
return "resuit " + id;
}
}
public class Callabletest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
ArrayList<Future<String>> futures = new ArrayList<Future<String>>();
for(int i=1;i<=5;i++){
futures.add(executorService.submit(new MyCallableTask(i)));
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(Future<String> fu:futures){
//运行完成返回true
if(fu.isDone()) {
try {
System.out.println(fu.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}else{
System.out.println("MyCallableTask任务未完成!");
}
}
executorService.shutdown();
}
}
CountDownLatch(倒计时计算器)
是一个工具类,起到线程之间通信的作用
package com.boom.example.demo.aa;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(5);
for(int i = 1;i <=5;i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName());
countDownLatch.countDown();
},String.valueOf(i)).start();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("mian");
}
}
CyclicBarrier(加法计算器)
是一个同步的辅助类,允许一组线程相互之间等待,达到一个共同点,再继续执行
Semaphore
也是线程同步辅助类,可维护当前线程个数,并提供同步机制
package com.boom.example.demo.aa;
import java.util.concurrent.Semaphore;
public class Semaphoredemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for(int i=1;i<=6;i++){
new Thread(()->{
try {
semaphore.acquire();//获取一个线程许可
System.out.println(Thread.currentThread().getName());
System.out.println("进入车库");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
System.out.println("离开车库");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();//释放许可
}
},String.valueOf(i)).start();
}
}
}
ReadWriteLock
Synchronized和ReentrantLock都是排他锁,同一时刻只允许一个线程访问共享资源,在平时场景会经常遇到读多写少的场景,在这种场景下,每次只允许一个线程访问,效率比较低下
读写锁就因运而生了,它由读锁和写锁两部分组成,读写锁的特点:同一时刻允许多个线程对共享资源进行读操作,同一时刻只允许一个线程对共享资源进行写操作,当写操作的时候,同一时刻的其他线程的读操作会被阻塞,当读操作的时候,同一时刻的写操作会被阻塞,读锁也被称共享锁,写锁被称为排它锁
在java中通过ReadWriteLock来实现读写锁,ReadWriteLock是接口,ReentrantReadWriteLock是它的具体实现方法,通过ReadLock和WriteLock两个内部类来实现读锁和写锁
package com.boom.example.demo.aa;
import java.lang.invoke.VarHandle;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCacheLock myCacheLock = new MyCacheLock();
for(int i=1;i<=5;i++){
final int temp = i;
new Thread(()->{
myCacheLock.put(String.valueOf(temp),temp);
},String.valueOf(i)).start();
}
for(int i=1;i<=5;i++){
final int temp = i;
new Thread(()->{
myCacheLock.get(String.valueOf(temp));
},String.valueOf(i)).start();
}
}
}
class MyCacheLock{
private volatile HashMap<String,Object> hashMap = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(String s,Object obj){
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "写入" + obj);
hashMap.put(s,obj);
System.out.println(Thread.currentThread().getName() + "写入完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
public void get(String s){
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "读取" + s);
hashMap.get(s);
System.out.println(Thread.currentThread().getName() + "读取完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
}
BlockingQueue
四组API
SynchronizedQueue
不存储元素