前言:

本文内容:CopyOnWriteArraySet、ConcurrentHashMap、走进Callable

推荐免费JUC并发编程视频:【狂神说Java】JUC并发编程最新版通俗易懂_哔哩哔哩_bilibili

CopyOnWriteArraySet

多线程下Set安全问题

并发异常:java.util.ConcurrentModificationException

解决办法:

  1. Collections.synchronizedSet(new HashSet<>());
  2. new CopyOnWriteArraySet<>();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

package com.jokerdig.unsafe;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;

/**
* @author Joker大雄
* @data 2022/8/19 - 10:29
**/
// 报错:java.util.ConcurrentModificationException
public class SetTest {
public static void main(String[] args) {
// 报错
// Set<String> set = new HashSet<>();

// 1.Collections.synchronizedSet(new HashSet<>());
// Set<String> set = Collections.synchronizedSet(new HashSet<>());

// 2.new CopyOnWriteArraySet<>();
Set<String> set = new CopyOnWriteArraySet<>();
for(int i=1;i<10;i++){
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}

HashSet的底层

1
2
3
4
5
6
7
8
public HashSet(){
map = new HashMap<>();
}
// add -> map key是无法重复的
public boolean add(E e){
return map.put(e,PRESENT)==null;
}
private static final Object PRESENT = new Object();

ConcurrentHashMap

多线程下Map安全问题

并发异常:java.util.ConcurrentModificationException

解决办法:

  1. Collections.synchronizedMap(new HashMap<>());
  2. new ConcurrentHashMap<>();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.jokerdig.unsafe;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
* @author Joker大雄
* @data 2022/8/19 - 11:36
**/
// 报错:java.util.ConcurrentModificationException
public class MapTest {
public static void main(String[] args) {
// 工作中不适用HashMap
// 默认等价于 new HashMap(16,0.75)
// 会报错
// Map<String,String> map = new HashMap<>();

// 1.Collections.synchronizedMap(new HashMap<>());
// Map<String,String> map = Collections.synchronizedMap(new HashMap<>());

// 2.new ConcurrentHashMap<>();
Map<String,String> map = new ConcurrentHashMap<>();
for(int i=1;i<10;i++){
new Thread(()->{
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}

}

走进Callable

概述

Callable接口类似于Runnable,它们都是为其实例可能由另一个线程执行的类而设计的,但是,Runnable不能返回结果,也不能抛出被检查的异常。

Runnable

1
2
3
4
5
6
7
8
// 没有返回值也不能抛出被检查的异常
class myThread implements Runnable{

@Override
public void run() {

}
}

代码测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.jokerdig.callable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
* @author Joker大雄
* @data 2022/8/19 - 12:43
**/
public class CallableTest {

public static void main(String[] args) throws ExecutionException, InterruptedException {
// new Thread(new Runnable(...)).start();
// new Thread(new FutureTask<V>()).start();
// new Thread(new FutureTask<V>(Callable)).start();
myThread myThread = new myThread();
// 适配类
FutureTask futureTask = new FutureTask(myThread);
// 启动 callable
new Thread(futureTask,"A").start();
// 有AB两个线程,结果会被缓存,效率高
new Thread(futureTask,"B").start();
// callable 返回值 get()方法可能会产生阻塞,把它放到最后或者使用异步通信
Integer out = (Integer) futureTask.get();
System.out.println(out);
}
}
// 泛型的值和返回值的类型相同
class myThread implements Callable<Integer> {


@Override
public Integer call() throws Exception {
System.out.println("call()");
// 耗时操作
return 1024;
}
}

运行结果

1
2
3
4
call()
1024

Process finished with exit code 0

注意:

  1. 有缓存
  2. 结果耗时,会发生阻塞!