【Java】Java并发容器J.U.C

CopyOnWriteArrayList介绍

 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(); //释放锁

}

}

public E get(int index) {

return get(getArray(), index);

}

  • 如果写操作未完成,那么直接读取原数组的数据;
  • 如果写操作完成,但是引用还未指向新数组,那么也是读取原数组数据;
  • 如果写操作完成,并且引用已经指向了新的数组,那么直接从新数组中读取数据。

CopyOnWriteArrayList多线程代码演示。

package com.rumenz.task;

import java.util.List;

import java.util.concurrent.*;

//线程安全

public class CopyOnWrireArrayListExample {

public static Integer clientTotal=5000;

public static Integer threadTotal=200;

private static List<Integer> list=new CopyOnWriteArrayList();

public static void main(String[] args) throws Exception{

ExecutorService executorService = Executors.newCachedThreadPool();

final Semaphore semaphore=new Semaphore(threadTotal);

final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);

for (int i = 0; i < clientTotal; i++) {

final Integer j=i;

executorService.execute(()->{

try{

semaphore.acquire();

update(j);

semaphore.release();

}catch (Exception e){

e.printStackTrace();

}

countDownLatch.countDown();

});

}

countDownLatch.await();

executorService.shutdown();

System.out.println("size:"+list.size());

}

private static void update(Integer j) {

list.add(j);

}

}

//size:5000

CopyOnWriteArrayList使用场景

  • 由于在add的时候需要拷贝原数组,如果原数组内容比较多,比较大,可能会导致young gcfull gc
  • 不能用于实时读的场景,像拷贝数组,新增元素都需要时间,所以调用get操作后,有可能得到的数据是旧数据,虽然CopyOnWriteArrayList能做到最终一致性,但是没有办法满足实时性要求。
  • CopyOnWriteArrayList适合读多写少的场景,比如白名单,黑名单等场景

  • CopyOnWriteArrayList由于add时需要复制数组,所以不适用高性能的互联网的应用。

CopyOnWriteArraySet介绍

public CopyOnWriteArraySet() {

al = new CopyOnWriteArrayList<E>();

}

CopyOnWriteArraySet多线代码演示

package com.rumenz.task;

import java.util.List;

import java.util.Set;

import java.util.concurrent.*;

//线程安全

public class CopyOnWrireArraySetExample {

public static Integer clientTotal=5000;

public static Integer threadTotal=200;

private static Set<Integer> set=new CopyOnWriteArraySet();

public static void main(String[] args) throws Exception{

ExecutorService executorService = Executors.newCachedThreadPool();

final Semaphore semaphore=new Semaphore(threadTotal);

final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);

for (int i = 0; i < clientTotal; i++) {

final Integer j=i;

executorService.execute(()->{

try{

semaphore.acquire();

update(j);

semaphore.release();

}catch (Exception e){

e.printStackTrace();

}

countDownLatch.countDown();

});

}

countDownLatch.await();

executorService.shutdown();

System.out.println("size:"+set.size());

}

private static void update(Integer j) {

set.add(j);

}

}

//size:5000

CopyOnWriteArraySet使用场景

  • 适用于set大小一般很小,读操作远远多于写操作的场景

ConcurrentSkipListSet

public ConcurrentSkipListSet() {

m = new ConcurrentSkipListMap<E,Object>();

}

public boolean addAll(Collection<? extends E> c) {

boolean modified = false;

for (E e : c)

if (add(e))

modified = true;

return modified;

}

public boolean removeAll(Collection<?> c) {

Objects.requireNonNull(c);

boolean modified = false;

Iterator<?> it = iterator();

while (it.hasNext()) {

if (c.contains(it.next())) {

it.remove();

modified = true;

}

}

return modified;

}

public boolean containsAll(Collection<?> c) {

for (Object e : c)

if (!contains(e))

return false;

return true;

}

ConcurrentSkipListSet代码演示

package com.rumenz.task;

import java.util.ArrayList;

import java.util.List;

import java.util.Set;

import java.util.concurrent.*;

//线程安全

public class CopyOnWrireArrayListExample {

public static Integer clientTotal=5000;

public static Integer threadTotal=200;

private static Set<Integer> set= new ConcurrentSkipListSet();

public static void main(String[] args) throws Exception{

ExecutorService executorService = Executors.newCachedThreadPool();

final Semaphore semaphore=new Semaphore(threadTotal);

final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);

for (int i = 0; i < clientTotal; i++) {

final Integer j=i;

executorService.execute(()->{

try{

semaphore.acquire();

update(j);

semaphore.release();

}catch (Exception e){

e.printStackTrace();

}

countDownLatch.countDown();

});

}

countDownLatch.await();

executorService.shutdown();

System.out.println("size:"+set.size());

}

private static void update(Integer r) {

set.add(r);

}

}

//size:5000

ConcurrentHashMap

ConcurrentHashMap代码演示案例

package com.rumenz.task;

import java.util.Map;

import java.util.Set;

import java.util.concurrent.*;

//线程安全

public class ConcurrentHashMapExample {

public static Integer clientTotal=5000;

public static Integer threadTotal=200;

private static Map<Integer,Integer> map=new ConcurrentHashMap<Integer,Integer>();

public static void main(String[] args) throws Exception{

ExecutorService executorService = Executors.newCachedThreadPool();

final Semaphore semaphore=new Semaphore(threadTotal);

final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);

for (int i = 0; i < clientTotal; i++) {

final Integer j=i;

executorService.execute(()->{

try{

semaphore.acquire();

update(j);

semaphore.release();

}catch (Exception e){

e.printStackTrace();

}

countDownLatch.countDown();

});

}

countDownLatch.await();

executorService.shutdown();

System.out.println("size:"+map.size());

}

private static void update(Integer j) {

map.put(j, j);

}

}

//size:5000

ConcurrentSkipListMap

【Java】Java并发容器J.U.C

ConcurrentSkipListMap代码案例

package com.rumenz.task;

import java.util.Map;

import java.util.concurrent.*;

//线程安全

public class ConcurrentSkipListMapExample {

public static Integer clientTotal=5000;

public static Integer threadTotal=200;

private static Map<Integer,Integer> map=new ConcurrentSkipListMap<>();

public static void main(String[] args) throws Exception{

ExecutorService executorService = Executors.newCachedThreadPool();

final Semaphore semaphore=new Semaphore(threadTotal);

final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);

for (int i = 0; i < clientTotal; i++) {

final Integer j=i;

executorService.execute(()->{

try{

semaphore.acquire();

update(j);

semaphore.release();

}catch (Exception e){

e.printStackTrace();

}

countDownLatch.countDown();

});

}

countDownLatch.await();

executorService.shutdown();

System.out.println("size:"+map.size());

}

private static void update(Integer j) {

map.put(j, j);

}

}

//size:5000

ConcurrentHashMapConcurrentSkipListMap的对比

  • ConcurrentHashMapConcurrentSkipListMap性能要好一些。

  • ConcurrentSkipListMapkey是有序的,ConcurrentHashMap做不到。

  • ConcurrentSkipListMap支持高并发,它的时间复杂度是log(N),和线程数无关,也就是说任务一定的情况下,并发的线程越多,ConcurrentSkipListMap的优势就越能体现出来。

关注微信公众号:【入门小站】解锁更多知识点

【Java】Java并发容器J.U.C

以上是 【Java】Java并发容器J.U.C 的全部内容, 来源链接: utcz.com/a/96437.html

回到顶部