这篇文章将为大家详细讲解有关java高并发同步容器指的是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。
在java中同步容器主要包括两类:
ArrayList -> Vector,Stack; HashMap -> HashTable(key,value不能为null)
Collections.synchronizedXXX(List, Set, Map)
Vector实现了List接口,实际上就是一个数组。与ArrayList非常类似。但是Vector中的所有方法都是使用synchronized方法修饰的方法,进行了同步的措施。因此在多线程环境下使用ArrayList对象时,如果被多个线程共享使用可以换成同步的Vector,这样的话线程安全型会更好一些(而不是完全线程安全的)。
@Slf4j @ThreadSafe public class VectorExample1 { // 请求总数 public static int clientTotal = 5000; // 同时并发执行的线程数 public static int threadTotal = 200; private static List<Integer> 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); } }
这样输出的结果就是预期的结果。
@NotThreadSafe public class VectorExample2 { private static Vector<Integer> 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中的方法也使用了synchronized修饰了,实际上Stack类继承了Vector类。
HashTable实现了Map接口,与HashMap很相似,但是HashTable进行了同步处理,方法也是使用了synchronized进行了修饰。但是在使用HashTable时一定要注意key和value是不能为null的。
将新建ArrayList、HashSet、HashMap对象由Collections产生:
private static List<Integer> list = Collections.synchronizedList(new ArrayList<>()); private static Set<Integer> set = Collections.synchronizedSet(new HashSet<>()); private static Map<Integer, Integer> map = Collections.synchronizedMap(new HashMap<>());
public class VectorExample3 { //Exception in thread "main" java.util.ConcurrentModificationException private static void test1(Vector<Integer> 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<Integer> v1){ //iterator Iterator<Integer> integerIterator = v1.iterator(); while (integerIterator.hasNext()) { Integer i = integerIterator.next(); if(i.equals(3)){ v1.remove(i); } } } // success private static void test3(Vector<Integer> v1){ for(int i = 0; i < v1.size(); i++) { if(v1.equals(3)){ v1.remove(i); } } } public static void main(String[] args) { Vector<Integer> vector = new Vector<>(); vector.add(1); vector.add(2); vector.add(3); test1(vector); } }
如果使用了Foreach或者迭代器来循环我们的集合时,尽量不要在循环中做集合的删除操作,如果要做remove操作时,建议在遍历的过程中发现需要删除的值然后做一个标记,在遍历结束后在执行相应的remove操作。在多线程情况下出现异常的情况会更大。
关于java高并发同步容器指的是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。