JUC并发编程-集合不安全情况以及Callable线程创建方式

6. 集合不安全

1)List 不安全

java 复制代码
//java.util.ConcurrentModificationException 并发修改异常!
public class ListTest {
    public static void main(String[] args) {

        List<Object> arrayList = new ArrayList<>();

        for(int i=1;i<=30;i++){
            new Thread(()->{
                arrayList.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(arrayList);
            },String.valueOf(i)).start();
        }

    }
}

ArrayList 在并发情况下是不安全的

解决方案 :

1.Vector

2.Collections.synchonizedList()

3. CopyOnWriteArrayList

核心思想 是,如果有多个调用者(Callers)同时要求相同的资源 (如内存或者是磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源直到某个调用者视图修改资源内容时,系统才会真正复制一份专用副本(private copy)给该调用者而其他调用者所见到的最初的资源仍然保持不变这过程对其他的调用者都是透明的(transparently) 。此做法主要的优点如果调用者没有修改资源,就不会有副本(private copy)被创建,因此多个调用者只是读取操作时可以共享同一份资源

的时候 需要加锁 ,如果读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读还是会读到旧的数据 ,因为写的时候不会锁住旧的CopyOnWriteArrayList

多个线程调用的时候list读取的时候,固定的写入(存在覆盖操作);在写入的时候避免覆盖,造成数据错乱的问题;

CopyOnWriteArrayListVector效率更高

Vector底层是使用synchronized关键字来实现的 ,效率低

CopyOnWriteArrayList使用的是Lock锁,效率会更加高效!

2)set 不安全

Set和List同理可得: 多线程 情况下,普通的Set集合是线程不安全的

解决方案还是两种:

  • 使用Collections工具类synchronized包装的Set类
  • 使用CopyOnWriteArraySet 写入复制的JUC解决方案

HashSet底层 :

hashSet底层就是一个HashMap

3)Map不安全

java 复制代码
//map 是这样用的吗?  不是,工作中不使用这个
//默认等价什么? new HashMap<>(16,0.75);
Map<String, String> map = new HashMap<>();
//加载因子、初始化容量

默认加载因子是0.75,默认的初始容量是16

同样的HashMap基础类也存在并发修改异常

java 复制代码
public class MapTest {
    public static void main(String[] args) {
        //map 是这样用的吗?  不是,工作中不使用这个
        //默认等价什么? new HashMap<>(16,0.75);
        /**
         * 解决方案
         * 1. Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
         *  Map<String, String> map = new ConcurrentHashMap<>();
         */
        Map<String, String> map = new ConcurrentHashMap<>();
        //加载因子、初始化容量
        for (int i = 1; i < 100; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
                System.out.println(map);
            },String.valueOf(i)).start();
        }
    }
}

TODO:研究ConcurrentHashMap底层原理:

7. Callable

1、可以有返回值;
2、可以抛出异常;
3、方法不同,run()/call()

Callable和Runnable()区别和联系:

理解Callable怎么和Thread建立联系的!!!

futureTask是一个适配类

Callable的返回结果在futureTask中

获取返回值的操作,可能会产生阻塞

callable线程的结果会缓存,效率更高

java 复制代码
public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        for (int i = 1; i < 10; i++) {
            MyThread1 myThread1 = new MyThread1();

            FutureTask<Integer> futureTask = new FutureTask<>(myThread1);
            // 放入Thread中使用,结果会被缓存
            new Thread(futureTask,String.valueOf(i)).start();
            // 这个get方法可能会被阻塞,如果在call方法中是一个耗时的方法,所以一般情况我们会把这个放在最后,或者使用异步通信
            int a = futureTask.get();
            System.out.println("返回值:" + s);
        }

    }

}
class MyThread1 implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("call()");
        return 1024;
    }
}

JUC并发编程-集合不安全情况以及Callable线程创建方式 到此完结,笔者归纳、创作不易,大佬们给个3连再起飞吧

相关推荐
程序员一点2 天前
Python并发编程(1)——Python并发编程的几种实现方式
python·多线程·并发编程·多进程
这题怎么做?!?8 天前
【Linux】多线程:线程池的创建、日志类、RAII互斥锁、单例模式:饿汉方式与懒汉方式
linux·c语言·c++·单例模式·线程池·多线程·日志
程序猿进阶9 天前
New major version of npm available! 8.3.1 -> 10.8.3 报错
java·开发语言·前端·设计模式·npm·node.js·并发编程
写hello world都有bug10 天前
谈谈Redisson分布式锁的底层实现原理
redis·多线程·分布式锁
hn_tzy10 天前
C++11中引入的thread
开发语言·c++·多线程·条件变量·thread·互斥锁·同步
无理 Java13 天前
【技术解析】消息中间件MQ:从原理到RabbitMQ实战(深入浅出)
java·分布式·后端·rabbitmq·多线程·mq·消息中间件
亿牛云爬虫专家18 天前
优化数据的抓取规则:减少无效请求
python·数据采集·多线程·爬虫代理·数据抓取·代理ip·房价
亿牛云爬虫专家18 天前
如何通过subprocess在数据采集中执行外部命令 —以微博为例
爬虫·python·数据采集·多线程·代理ip·subprocess·微博
lazy★boy19 天前
JUC学习笔记(一)
juc