解决ArrayList线程不安全
并发下ArrayList线程不安全,解决方法:
Vector
- List<·String> list = new Vector();
synchronizedList
- List<·String> list = Collections.synchronizedList(new ArrayList<>())
CopyOnWriteArrayList
- CopyOnWriteArrayList<·String> list = new CopyOnWriteArrayList<>();
/**
* 并发下ArrayList线程不安全,解决方法
* 1.List<String> list = new Vector();
* 2.List<String> list = Collections.synchronizedList(new ArrayList<>());
* 3.CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
* @Author Weton Li
* @Date 2021/2/9 17:34
*/
public class ListTest {
public static void main(String[] args) {
// List<String> strings = Arrays.asList("1", "2", "3a");
// strings.forEach(System.out::println);
// ArrayList线程不安全
// List<String> list = new Vector(); // 性能差淘汰
// List<String> list = Collections.synchronizedList(new ArrayList<>());
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
for (int i = 1; i <= 10000; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
解决HashSet线程不安全
- Set set = Collections.synchronizedSet(new HashSet<>());
- CopyOnWriteArraySet set = new CopyOnWriteArraySet<>();
/**
* 解决HashSet线程不安全问题
* 1.Set<String> set = Collections.synchronizedSet(new HashSet<>());
* 2.
* @Author Weton Li
* @Date 2021/2/9 18:43
*/
public class SetTest {
public static void main(String[] args) {
// HashSet<String> set = new HashSet<>(); // 报ConcurrentModificationException
// Set<String> set = Collections.synchronizedSet(new HashSet<>());
CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
for (int i = 1; i <= 100; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
解决HashMap线程不安全
- Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());
- ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>();
/**
* @Author Weton Li
* @Date 2021/2/9 20:05
*/
public class MapTest {
public static void main(String[] args) {
// HashMap<Object, Object> map = new HashMap<>(); // 加载因子,初始化容量
// Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());
ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>();
for (int i = 1; i < 30; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
Callable
相比Runnable有返回值,且能够抛出异常,方法是call()
使用步骤:
自定义类实现Callable接口,泛型指定返回值类型,重写call()方法,在主函数中使用适配器模式创建FutureTask对象将自定义类对象丢给他,创建新线程,将适配器对象传给线程参数中
注意:
- futureTask.get()方法可能会产生阻塞,把它放到最后获取。或者使用异步通信。
- call()方法有缓存,启动三个线程,只会打印一次call()方法中打印的call()字符串
写入时复制,在写入的时候避免覆盖,造成数据问题
读写分离
计算机程序设计领域的优化策略:COW策略
不用Vector而用CopyOnWriteArrayList原因,Vector底层方法使用synchronized效率低,而cowArrayList则使用lock锁,使用了读写分离。
/**
* @Author Weton Li
* @Date 2021/2/9 20:27
*/
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// new Thread(new MyThread()).start();
MyThread myThread = new MyThread();
FutureTask<Integer> futureTask = new FutureTask<>(myThread);
new Thread(futureTask,"a").start(); // 如何启动Callable
new Thread(futureTask,"b").start(); // 结果会被缓存,效率高
Integer integer = futureTask.get(); // 这个get方法可能会产生阻塞,把它放在最后获取。 或者使用异步通信
System.out.println(integer);
}
}
//class MyThread implements Runnable {
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("call()");
return 1024;
}
}