多线程进阶JUC之解决线程不安全问题和Callable的使用与注意项

解决ArrayList线程不安全

并发下ArrayList线程不安全,解决方法:

Vector

  1. List<·String> list = new Vector();

synchronizedList

  1. List<·String> list = Collections.synchronizedList(new ArrayList<>())

CopyOnWriteArrayList

  1. 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线程不安全

  1. Set set = Collections.synchronizedSet(new HashSet<>());
  2. 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线程不安全

  1. Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());
  2. 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对象将自定义类对象丢给他,创建新线程,将适配器对象传给线程参数中

注意:

  1. futureTask.get()方法可能会产生阻塞,把它放到最后获取。或者使用异步通信。
  2. 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;
    }
}

猜你喜欢

转载自blog.csdn.net/m0_47119598/article/details/113774250
今日推荐