千家信息网

java高并发同步容器指的是什么

发表于:2025-02-03 作者:千家信息网编辑
千家信息网最后更新 2025年02月03日,这篇文章将为大家详细讲解有关java高并发同步容器指的是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。在java中同步容器主要包括两类:Array
千家信息网最后更新 2025年02月03日java高并发同步容器指的是什么

这篇文章将为大家详细讲解有关java高并发同步容器指的是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

在java中同步容器主要包括两类:

  • ArrayList -> Vector,Stack; HashMap -> HashTable(key,value不能为null)

  • Collections.synchronizedXXX(List, Set, Map)

Vector

Vector实现了List接口,实际上就是一个数组。与ArrayList非常类似。但是Vector中的所有方法都是使用synchronized方法修饰的方法,进行了同步的措施。因此在多线程环境下使用ArrayList对象时,如果被多个线程共享使用可以换成同步的Vector,这样的话线程安全型会更好一些(而不是完全线程安全的)。

@Slf4j@ThreadSafepublic class VectorExample1 {    // 请求总数    public static int clientTotal = 5000;    // 同时并发执行的线程数    public static int threadTotal = 200;    private static List list = new Vector<>();    public static void main(String[] args) throws InterruptedException {        //线程池        ExecutorService executorService = Executors.newCachedThreadPool();        //定义信号量        final Semaphore semaphore = new Semaphore(threadTotal);        //定义计数器        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);        for(int i = 0; i < clientTotal; i++) {            final int count  = i;            executorService.execute(() ->{                try {                    semaphore.acquire();                    update(count);                    semaphore.release();                } catch (InterruptedException e) {                    log.error("exception", e);                }                countDownLatch.countDown();            });        }        countDownLatch.await();        executorService.shutdown();        log.info("size:{}",list.size()) ;    }    public static void update(int i) {        list.add(i);    }}

这样输出的结果就是预期的结果。

为什么说同步容器不是线程安全的?

@NotThreadSafepublic class VectorExample2 {    private static Vector vector = new Vector<>();    public static void main(String[] args) {        while (true){            for (int i = 0;i < 10;i++) {                vector.add(i);            }            Thread thread1 = new Thread(){                @Override                public void run() {                    for (int i = 0;i < vector.size();i++) {                        vector.remove(i);                    }                }            };            Thread thread2 = new Thread(){                @Override                public void run() {                    for (int i = 0;i < vector.size();i++) {                        vector.get(i);                    }                }            };            thread1.start();            thread2.start();        }    }}

运行,抛出异常:

Exception in thread "Thread-611" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 5        at java.util.Vector.get(Vector.java:748)        at com.vincent.example.syncContainer.VectorExample2$2.run(VectorExample2.java:25)Exception in thread "Thread-1759" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 21        at java.util.Vector.get(Vector.java:748)        at com.vincent.example.syncContainer.VectorExample2$2.run(VectorExample2.java:25)

原因:get发生越界肯定是remove方法引起的,vector虽然能保证同一时刻只能有一个线程能访问他,但是不排除有这种可能:当某个线程某个时刻执行到int i = 0;i < vector.size()时,vector.size()返回10,i=9;而另外一个线程正好将i=9的vector移除掉了,这时get方法想调用i=9的元素就会出现数组越界的异常。

这个例子演示了两个同步容器的两个同步方法因为操作顺序的差异,在不同线程里面可能会触发线程不安全的问题。因此为了保证线程安全,必须在方法调用端做一些额外的同步措施才可以。在使用同步容器时并不是在所有场合下都是线程安全的。

Stack

Stack中的方法也使用了synchronized修饰了,实际上Stack类继承了Vector类。

HashTable

HashTable实现了Map接口,与HashMap很相似,但是HashTable进行了同步处理,方法也是使用了synchronized进行了修饰。但是在使用HashTable时一定要注意key和value是不能为null的。

Collections

将新建ArrayList、HashSet、HashMap对象由Collections产生:

private static List list = Collections.synchronizedList(new ArrayList<>());private static Set set = Collections.synchronizedSet(new HashSet<>());private static Map map = Collections.synchronizedMap(new HashMap<>());

在集合遍历过程中删除操作

public class VectorExample3 {    //Exception in thread "main" java.util.ConcurrentModificationException    private static void test1(Vector v1){ //foreach        for(Integer i: v1){            if(i.equals(3)){                v1.remove(i);            }        }    }    //Exception in thread "main" java.util.ConcurrentModificationException    private static void test2(Vector v1){ //iterator        Iterator integerIterator = v1.iterator();        while (integerIterator.hasNext()) {            Integer i = integerIterator.next();            if(i.equals(3)){                v1.remove(i);            }        }    }    // success    private static void test3(Vector v1){        for(int i = 0; i < v1.size(); i++) {            if(v1.equals(3)){                v1.remove(i);            }        }    }    public static void main(String[] args) {        Vector vector = new Vector<>();        vector.add(1);        vector.add(2);        vector.add(3);        test1(vector);    }}

如果使用了Foreach或者迭代器来循环我们的集合时,尽量不要在循环中做集合的删除操作,如果要做remove操作时,建议在遍历的过程中发现需要删除的值然后做一个标记,在遍历结束后在执行相应的remove操作。在多线程情况下出现异常的情况会更大。

关于java高并发同步容器指的是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

0