Java如何保证集合是线程安全的?(代码实践抛砖引玉)

在Java中绝大部分的集合像什么ArrayList、HashMap等绝大部分不是线程安全的。仅有的线程安全的实现,像HashTable、Vector等在性能上又不好。但是不要怕啊。我们大Java还有并发包(Java.util.concurrent)啊,为高度并发需求提供了全面安全的支持。

一、在传统的集合框架中,如何解决线程安全问题。

当然,除了Hashtable等同步容器,我们可以使用同步包装器创建一个线程安全的容器。但是这种方式用的是非常粗的同步方式,在高并发情况下,性能比较低下。

具体的位置如下

在这里插入图片描述

下面楼主写了有一些实践的代码:

package com.newframe.controllers.api;

import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.SynchronousQueue;

/**
 * 测试传统线程安全的集合类
 */
public class TestTraditionSyn {

    public static void main(String[] args) {

        /**
         * 1。在传统的集合框架中。
         * 除了Hashtable这个是线程安全的同步容器。
         * 他的实现基本上就是将Put、get、size等各种
         * 方法的操作加上"synchronized"。这就导致了所有的并发操作都在竞争同一把锁
         * 一个线程在进行同步操作时,其他线程只能等待,大大降低了并发执行的效率
         * (当然这个因为同步的线程开销较大,不推荐使用)
         * 还可以通过调用Collections工具类提供的包装类。来构造线程安全的同步包装容器,如下所示
         */
        //构造一个线程安全的List
        List<String> list = Collections.synchronizedList(new ArrayList<>());
        list.add("hello");
        list.add("world");

        Iterator iterator1 = list.iterator();
        while (iterator1.hasNext()){
            System.out.println(iterator1.next());
        }

        //构造一个线程安全的Map
        Map<String,Object> map1 = Collections.synchronizedMap(new HashMap<>());
        map1.put("1","wang");
        map1.put("2","dong");

        map1.forEach((key,value) ->{
            System.out.println("map1:" + key + "," + value);
        });
    }
}

二、重头戏首选的肯定还是我们的Java并发包啊

具体位置如下:

在这里插入图片描述

下面楼主也写了一些示范如何使用的简单代码:

package com.newframe.controllers.api;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.SynchronousQueue;

/**
 * 测试并发包中的集合类
 */
public class TestConcurrentSyn {

    public static void main(String[] args) {

        /**
         * 2。并发包。在工作中,我们更加普遍的是选择利用并发包提供
         * 适合在高度并发的环境下使用
         * 线程安全容器类
         * 这个只要你是按照并发包的标准创建的集合,都是线程安全的。
         */
        //关于map的ConcurrentHashMap
        ConcurrentHashMap<String,Object> map2 = new ConcurrentHashMap<>();
        map2.put("1","我是并发包直接构建的");
        map2.put("2","我是线程安全的Map容器,ConcurrentHashMap");
        map2.forEach((key,value) ->{
            System.out.println("map2:" + key + "," + value);
        });

        //关于list的CopyOnWriteArrayList
        CopyOnWriteArrayList<Integer> list2 = new CopyOnWriteArrayList<>();
        list2.add(67612);
        list2.add(67362);
        list2.forEach(list ->{
            System.out.println(list);
        });

        /**
         * 并发包中的线程安全队列
         */
        //ArrayBlockingQueue
        ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue(10);
        arrayBlockingQueue.add("1");
        arrayBlockingQueue.add("3");
        arrayBlockingQueue.forEach(queue->{
            System.out.println(queue);
        });
    }
}

三、关于Java8以后的ConcurrentHashMap的一点思考。

ConcurrentHashMap的设计实现是一直都在不断的演化,性能也是在不断的提高。

早期的ConcurrentHashMap,其实现主要是基于:

  • 分离锁。在内部进行分段(Segment),里面则是HashEntry的数组,和HashMap类似,哈希相同的条目也是以链表的形式存放。
  • HashEntry内部使用volatile的value字段来保证可见性。

那么在Java8中,这个有什么变化呢?

  • 在结构上,虽然仍然有Segment定义,但是仅仅是为了给旧版本兼容。初始化已经改成了Lazy-load的形式了,有效避免了初始化开销。
  • 数据存储利用的是Volatile来保证可见性。如下图:

在这里插入图片描述

好啦,关于这个里面的东西太多了,还需要深入研究,当然,在工作中如果能明确应用场景,做出正确的选择才是关键。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值