11.CopyOnWriteArrayList
public class ListTest {
public static void main(String[] args) {
//并发下ArrayList不安全
/**
* 解决方法:
* 1. List<Integer> list = new Vector<>();
* 2. List<Integer> list = Collections.synchronizedList(new ArrayList<>());
* 3. List<Integer> list = new CopyOnWriteArrayList<>()
*/
//CopyOnWrite 写入时复制 COW 计算机程序设计领域的一种优化策略
//多个线程调用的时候,list,读取的时候,固定的,写入(覆盖)
//在写入的时候避免覆盖,造成数据问题
//读写分离
//CopyOnWriteArrayList 比 Vector 的优势
List<Integer> list = new CopyOnWriteArrayList<>();
for (int i = 1; i <= 1000; i++) {
final int finalI = i;
new Thread(() -> {
list.add(finalI);
}, String.valueOf(i)).start();
}
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
源码比较
CopyOnWriteArrayList的add源码
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
Vector的add源码
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
学习方法推荐:1.先会用,2.寻找其他解决方案,3.分析源码
12.CopyOnWriteArraySet
public class SetTest {
public static void main(String[] args) {
/**
* Set<Integer> set = new HashSet<>(); 不安全
* 解决方案:
* 1. Set<Integer> set = Collections.synchronizedSet(new HashSet<>());
* 2. Set<Integer> set = new CopyOnWriteArraySet<>();
*/
Set<Integer> set = new CopyOnWriteArraySet<>();
for (int i = 1; i <= 1000; i++) {
final int finalI = i;
new Thread(() -> {
set.add(finalI);
}).start();
}
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(set.size());
}
}
HashSet底层是什么?入参构造方法和add方法如下(源码)
public HashSet() {
map = new HashMap<>();
}
// 常量
private static final Object PRESENT = new Object();
//add set本质就是map key是无法重复的!
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
13.ConcurrentHashMap
public class MapTest {
public static void main(String[] args) {
//new HashMap<>() 等价于 new HashMap<>(16, 0.75f)
/**
* Map<Integer, String> map = new HashMap<>(); 不安全
* 解决方案:
* 1. Map<Integer, String> map = Collections.synchronizedMap(new HashMap<>());
* 2. Map<Integer, String> map = new ConcurrentHashMap<>();
*/
//看看官方api文档
Map<Integer, String> map = new ConcurrentHashMap<>();
for (int i = 1; i <= 1000; i++) {
final int finalI = i;
new Thread(() -> {
map.put(finalI, Thread.currentThread().getName());
}, String.valueOf(i)).start();
}
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(map.size());
}
}
14.走进Callable
- 可以有返回值
- 可以抛出异常
- 方法不同,call()
Runnable的Api文档
FutureTask的Api文档
public class CallableTest {
public static void main(String[] args) {
MyThread thread = new MyThread();
//Callable --- Runnable 中间转换(适配类)
FutureTask<String> futureTask = new FutureTask<>(thread);
//结果会被缓存,提高效率
new Thread(futureTask, "A").start();
new Thread(futureTask, "B").start();
//获取返回值
try {
//这个get方法可能会产生阻塞,把它放到最后
String s = futureTask.get();
//或者使用异步通信来处理
System.out.println(s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyThread implements Callable<String> {
@Override
public String call() {
System.out.println("call()");
//可能是耗时的操作
return "123";
}
}
输出
call()
123
细节;
- 有缓存
- 结果可能需要等待,会阻塞!
15.CountDownLatch
减法计数器
public class CountDownLatchDemo {
public static void main(String[] args) {
//总数是6 必须要执行的任务的时候再使用
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+" go out");
// 数量-1
countDownLatch.countDown();
}).start();
}
try {
//等待计数器归零,然后再往下执行
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("close door");
}
}
原理:
countDownLatch.countDown(); //数量-1
countDownLatch.await();//等待计数器归零,然后再往下执行
每次线程调用countDown()数量-1,假设计数器变成0,countDownLatch.await()就会被唤醒,继续执行!