Collection-List 安全VS不安全

2019-01-16  本文已影响15人  王小杰at2019

@[toc]

不安全示例

package cn.wyj.learn.juc;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

@Slf4j
public class CollectionListExample2ThreadSafe {

    private static Collection list = new ArrayList();
    //运行次数
    private static final int RUN_TOTAL = 5000;
    // 并发控制
    private static final int THREAD_TOTAL = 200;


    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Semaphore semaphore = new Semaphore(THREAD_TOTAL);
        for (int i = 0; i < RUN_TOTAL; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    list.add(1);
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
        // 需要等待成执行完
        executorService.awaitTermination(10, TimeUnit.SECONDS);
        log.info("list Size:{}", list.size());
    }


}


运行结果 1

21:06:36.240 [main] INFO cn.wyj.learn.juc.CollectionListExample1NoThreadSafe - list Size:4929

运行结果 2

Exception in thread "pool-1-thread-9" java.lang.ArrayIndexOutOfBoundsException: 366
    at java.util.ArrayList.add(ArrayList.java:459)
    at cn.wyj.learn.juc.CollectionListExample1NoThreadSafe.lambda$main$0(CollectionListExample1NoThreadSafe.java:28)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

安全写法1

    private static Collection list = CollectionUtils.synchronizedCollection(new ArrayList());

原因 .对原有api做了包裹处理

  /**
     * Constructor that wraps (not copies).
     * 
     * @param collection  the collection to decorate, must not be null
     * @throws IllegalArgumentException if the collection is null
     */
    protected SynchronizedCollection(Collection collection) {
        if (collection == null) {
            throw new IllegalArgumentException("Collection must not be null");
        }
        this.collection = collection;
        this.lock = this;
    }
    

    public boolean add(Object object) {
    synchronized (lock) {
        return collection.add(object);
    }
}

安全写法2

    private static Collection list = new Vector();

原因,Vector 容器本身就是安全的

 /**
     * Appends the specified element to the end of this Vector.
     *
     * @param e element to be appended to this Vector
     * @return {@code true} (as specified by {@link Collection#add})
     * @since 1.2
     */
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

安全写法3

    private static Collection list = new CopyOnWriteArrayList();

@since 1.5

Copy-On-Write简称COW,是一种用于程序设计中的优化策略。其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略。

容器声明

    private transient volatile Object[] array;

 /**
    * Appends the specified element to the end of this list.
    *
    * @param e element to be appended to this list
    * @return {@code true} (as specified by {@link Collection#add})
    */
   public boolean add(E e) {
       final ReentrantLock lock = this.lock;
       lock.lock();
       try {
           Object[] elements = getArray();
           int len = elements.length;
           Object[] newElements = Arrays.copyOf(elements, len + 1);
           newElements[len] = e;
           setArray(newElements);
           return true;
       } finally {
           lock.unlock();
       }
   }

 @SuppressWarnings("unchecked")
   private E get(Object[] a, int index) {
       return (E) a[index];
   }

   /**
    * {@inheritDoc}
    *
    * @throws IndexOutOfBoundsException {@inheritDoc}
    */
   public E get(int index) {
       return get(getArray(), index);
   }

image.png

安全写法4

自己实现并发控制,synchronized

package cn.wyj.learn.juc;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.*;

@Slf4j
public class CollectionListExample5ThreadSafe {

   private static Collection list = new ArrayList();
   //运行次数
   private static final int RUN_TOTAL = 5000;
   // 并发控制
   private static final int THREAD_TOTAL = 200;


   public static void main(String[] args) throws InterruptedException {
       ExecutorService executorService = Executors.newCachedThreadPool();
       Semaphore semaphore = new Semaphore(THREAD_TOTAL);
       for (int i = 0; i < RUN_TOTAL; i++) {
           executorService.execute(() -> {
               try {
                   semaphore.acquire();
                   add();
                   semaphore.release();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           });
       }
       executorService.shutdown();
       // 需要等待成执行完
       executorService.awaitTermination(10, TimeUnit.SECONDS);
       log.info("list Size:{}", list.size());
   }

   private static synchronized void add() {
       list.add(1);
   }


}

安全写法5

自己实现并发控制, 重入锁

package cn.wyj.learn.juc;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class CollectionListExample6ThreadSafe {

    private static Collection list = new ArrayList();
    //运行次数
    private static final int RUN_TOTAL = 5000;
    // 并发控制
    private static final int THREAD_TOTAL = 200;

    static Lock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Semaphore semaphore = new Semaphore(THREAD_TOTAL);
        for (int i = 0; i < RUN_TOTAL; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
        // 需要等待成执行完
        executorService.awaitTermination(10, TimeUnit.SECONDS);
        log.info("list Size:{}", list.size());
    }

    private static void add() {
        lock.lock();
        try {
            list.add(1);
        } finally {
            lock.unlock();
        }
    }


}

上一篇 下一篇

猜你喜欢

热点阅读