JUC集合&JUC辅助类&读写锁

JUC集合

List

CopyOnWriteArrayList

  • CopyOnWriteArrayList 写入时复制。cow,是计算机程序设计领域的一种优化策略。
  • 多个线程并发调用list时,为解决写入的时候避免覆盖造成数据的问题,
  • 写入的时候复制一个数据出来,写入后再插入进去
  • 性能 vector(synchronized)<CopyOnWriteArrayList (cow Arrays.copyOf())

                     我们知道ArrayList和LinkedList实现的List都是非线程安全的,于是就有了Vector,它是基于ArrayList的线程安全集合,但Vector无论是add方法还是get方法都加上了synchronized修饰,当多线程读写List必须排队执行,很显然这样效率比较是低下的。那有没有一种办法让效率提升,让当读List的时候线程是异步的,当写List是同步的呢?答案是CopyOnWriteArrayList,它是读写分离的,好处是提高线程访问效率。

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListTest {
    public static void main(String[] args) {
       /* 线程不安全ArrayList => ConcurrentModificationException并发修改异常。
        List<String> list = new ArrayList<String>();*/

        //List<String> list = Collections.synchronizedList(new ArrayList<String>());
        //List<String> list = new Vector<String>();
        List<String> list = new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }
}

 CopyOnWriteArrayList底层

 

 /**
     * Appends the specified element to the end of this list.
     * 将指定元素附加到此列表的末尾。*/
    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);//参数1:要复制的数组;参数2:返回新数组的长度
            newElements[len] = e;//新数组的最后位置是新插入的值e
            setArray(newElements);//新数组替换旧数组
            return true;
        } finally {
            lock.unlock();
        }
    }
}

Set

CopyOnWriteArraySet

       //Set<String> set = Collections.synchronizedSet(new HashSet<>());
        Set<String> set = new CopyOnWriteArraySet<String>();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                set.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(set);
            }, String.valueOf(i)).start();
        }

CopyOnWriteArraySet底层

CopyOnWriteArraySet的实现原理是通过CopyOnWriteArrayList的机制来实现的

class CopyOnWriteArraySet{
    private final CopyOnWriteArrayList<E> al;

    /**
     * Creates an empty set.
     */
    public CopyOnWriteArraySet() {
        //内部维护的是一个CopyOnWriteArrayList,
        //所以CopyOnWriteArraySet的实现原理是通过CopyOnWriteArrayList的机制来实现的;
        al = new CopyOnWriteArrayList<E>();
    }
    /**
     * Adds the specified element to this set if it is not already present.
     * More formally, adds the specified element {@code e} to this set if
     * the set contains no element {@code e2} such that
     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
     * If this set already contains the element, the call leaves the set
     * unchanged and returns {@code false}.
     *
     * @param e element to be added to this set
     * @return {@code true} if this set did not already contain the specified
     *         element
     *
     * 如果指定的元素尚不存在,则将其添加到此集合中。
     * 更正式地说,将指定元素 {@code e} 添加到此集合中,
     * 如果该集合不包含元素 {@code e2} 添加到集合中;
     * 如果这个集合已经包含该元素,则调用离开集合不变并返回 {@code false}。
     */
    public boolean add(E e) {
        return al.addIfAbsent(e);
    }
    /**
     * Appends the element, if not present.
     * 如果不存在,追加元素。
     * @param e element to be added to this list, if absent
     * @return {@code true} if the element was added
     */
    public boolean addIfAbsent(E e) {
        Object[] snapshot = getArray();
        return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
                addIfAbsent(e, snapshot);
    }
    /**
     * A version of addIfAbsent using the strong hint that given
     * recent snapshot does not contain e.
     */
    private boolean addIfAbsent(E e, Object[] snapshot) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] current = getArray();
            int len = current.length;
            if (snapshot != current) {
                // Optimize for lost race to another addXXX operation
                int common = Math.min(snapshot.length, len);
                for (int i = 0; i < common; i++)
                    if (current[i] != snapshot[i] && eq(e, current[i]))
                        return false;
                if (indexOf(e, current, common, len) >= 0)
                    return false;
            }
            Object[] newElements = Arrays.copyOf(current, len + 1);
            newElements[len] = e;//新数组替换旧数组
            setArray(newElements);//设置新数组
            return true;
        } finally {
            lock.unlock();
        }
    }
}

 扩展HashSet底层:

HashSet底层是是一个map

//PRESENT 固定的常量
private static final Object PRESENT = new Object();

public HashSet() {
  map = new HashMap<>();
}
//map key是无序不重复的。
public boolean add(E e) {
  return map.put(e, PRESENT)==null;
}

 BlockingQueue

ArrayBlockingQueue

方式 抛出异常 不抛出异常 等待超时 阻塞等待
添加  add offer
blockingQueue.offer(element,2,TimeUnit.SECONDS);
put  
删除 remove poll
blockingQueue.poll(2,TimeUnit.SECONDS);
take
检测队首元素 element peek    
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

public class ArrayBlockingQueueTest {
    static BlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);

    public static void main(String[] args) {
//       throwsException();
//       noThrowsException();
//        blockingWait();
        waitTimeOut();
    }

    /**
     * 超时等待
     */
    private static void waitTimeOut() {
        try {
            System.out.println("blockingQueue.offer(1) = " + blockingQueue.offer(1));
            System.out.println("blockingQueue.offer(2) = " + blockingQueue.offer(2));
            System.out.println("blockingQueue.offer(3) = " + blockingQueue.offer(3));
            //blockingQueue.offer(4,2,TimeUnit.SECONDS);
            System.out.println("blockingQueue.poll() = " + blockingQueue.poll());
            System.out.println("blockingQueue.poll() = " + blockingQueue.poll());
            System.out.println("blockingQueue.poll() = " + blockingQueue.poll());
            blockingQueue.poll(2,TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 阻塞等待
     */
    private static void blockingWait() {
        try {
            blockingQueue.put(1);
            blockingQueue.put(2);
            blockingQueue.put(3);
            //blockingQueue.put(4);//一直阻塞,不能blockingQueue.take()。
            System.out.println("blockingQueue.take() = " + blockingQueue.take());
            System.out.println("blockingQueue.take() = " + blockingQueue.take());
            System.out.println("blockingQueue.take() = " + blockingQueue.take());
            System.out.println("blockingQueue.take() = " + blockingQueue.take());//一直阻塞。

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 不抛出异常
     */
    private static void noThrowsException() {
        System.out.println("blockingQueue.offer(1) = " + blockingQueue.offer(1));
        System.out.println("blockingQueue.offer(2) = " + blockingQueue.offer(2));
        System.out.println("blockingQueue.offer(3) = " + blockingQueue.offer(3));
        System.out.println("blockingQueue.offer(4) = " + blockingQueue.offer(4));

        System.out.println("blockingQueue.poll() = " + blockingQueue.poll());
        System.out.println("blockingQueue.poll() = " + blockingQueue.poll());
        System.out.println("检测队首元素 = " + blockingQueue.peek());
        System.out.println("blockingQueue.poll() = " + blockingQueue.poll());
        System.out.println("blockingQueue.poll() = " + blockingQueue.poll());
        System.out.println("检测队首元素 = " + blockingQueue.peek());//队列为空时,返回null
    }

    /**
     * 抛出异常
     */
    private static void throwsException() {
        System.out.println("blockingQueue.add(1) = " + blockingQueue.add(1));
        System.out.println("blockingQueue.add(2) = " + blockingQueue.add(2));
        System.out.println("blockingQueue.add(3) = " + blockingQueue.add(3));
        //blockingQueue.add(4);//java.lang.IllegalStateException: Queue full
        System.out.println("blockingQueue.remove() = " + blockingQueue.remove());
        System.out.println("检测队首元素 = " + blockingQueue.element());
        System.out.println("blockingQueue.remove() = " + blockingQueue.remove());
        System.out.println("检测队首元素 = " + blockingQueue.element());
        System.out.println("blockingQueue.remove() = " + blockingQueue.remove());
        //System.out.println("blockingQueue.remove() = " + blockingQueue.remove());//java.util.NoSuchElementException
        System.out.println("检测队首元素 = " + blockingQueue.element());//队列为空时,java.util.NoSuchElementException
    }
}

 

SynchronousQueue

/**
 * A blocking queue其中每个插入操作必须等待另一个线程相应的删除操。
 * 同步队列没有任何内部容量。
 */
public class SynchronousQueueTest {
    public static void main(String[] args) {
        BlockingQueue<Object> blockingQueue = new SynchronousQueue<>();
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + " put 1");
                blockingQueue.put(1);
                System.out.println(Thread.currentThread().getName() + " put 2");
                blockingQueue.put(2);
                System.out.println(Thread.currentThread().getName() + " put 3");
                blockingQueue.put(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "=>" + blockingQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "=>" + blockingQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "=>" + blockingQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

 

 

 

Map

ConcurrentHashMap

ConcurrentHashMap底层

 

读写锁ReentrantReadWriteLock

读写、写写线程不能共存

写写线程可以共存

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReentrantReadWriteLockTest {
    public static void main(String[] args) {
        useLock();
    }

    public static void useLock() {
        MyCacheUseLock myCache = new MyCacheUseLock();
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(() -> {
                myCache.read(String.valueOf(temp));
            }, String.valueOf("线程") + temp).start();
        }
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(() -> {
                myCache.write(String.valueOf(temp), String.valueOf(temp));
            }, String.valueOf("线程") + temp).start();
        }
    }

    public static void notUseLock() {
        MyCache myCache = new MyCache();
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(() -> {
                myCache.read(String.valueOf(temp));
            }, String.valueOf("线程") + temp).start();
        }
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(() -> {
                myCache.write(String.valueOf(temp), String.valueOf(temp));
            }, String.valueOf("线程") + temp).start();
        }
    }
}

/**
 * 使用读写锁
 */
class MyCacheUseLock {
    private volatile Map<String, String> map = new HashMap<String, String>();
    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public void read(String key) {
        Lock readLock = readWriteLock.readLock();
        try {
            readLock.lock();
            System.out.println(Thread.currentThread().getName() + "读取" + key);
            map.get(key);
            System.out.println(Thread.currentThread().getName() + "读取完毕" + key);
        } finally {
            readLock.unlock();
        }

    }

    public void write(String key, String value) {
        Lock writeLock = readWriteLock.writeLock();
        try {
            writeLock.lock();
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入完毕" + key);
        } finally {
            writeLock.unlock();
        }
    }
}

/**
 * 不适用读写锁
 */
class MyCache {
    private volatile Map<String, String> map = new HashMap<String, String>();

    public void read(String key) {
        System.out.println(Thread.currentThread().getName() + "读取" + key);
        map.get(key);
        System.out.println(Thread.currentThread().getName() + "读取完毕" + key);

    }

    public void write(String key, String value) {
        System.out.println(Thread.currentThread().getName() + "写入" + key);
        map.put(key, value);
        System.out.println(Thread.currentThread().getName() + "写入完毕" + key);
    }
}

 JUC辅助工具类

CountDownLatch减法计数器

import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {
    public static void main(String[] args) {
        ClassRoom room = new ClassRoom();
        room.liveSchool();
    }
}
/**
*所有学生都离开教室才能锁门
*/ class ClassRoom{ CountDownLatch countDownLatch = new CountDownLatch(6);//6个学生都离开教师,才能锁教室门 public void liveSchool(){ try { for (int i = 1; i <= 6; i++) { new Thread(()->{ System.out.println(Thread.currentThread().getName()+"离开教室"); countDownLatch.countDown();//每次调用计数器都减1 },String.valueOf("学生"+i)).start(); } countDownLatch.await();//计数器归0,才能向下执行 System.out.println("6名学生都离开教室,关门!"); } catch (Exception e) { e.printStackTrace(); } } }

 

 

 

CyclicBarrier 加法计数器

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * 八人到齐会议室才能开会
 */
public class CyclicBarrierTest {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(8,()->{
            System.out.println("八人到齐会议室,开会!");
        });
        for (int i = 1; i <= 8; i++) {
            final int temp = i;
            new Thread(()->{//new Thread()是一个类,要访问其他类的属性,只能是常量
                System.out.println(Thread.currentThread().getName() + temp + "到达会议室");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                } catch (BrokenBarrierException e) { }

            }).start();
        }
    }
}

 

 

 

Semaphore

/**
 * 限流停车
 * 3个停车位,6辆车
 */
public class SemaphoreTest {
    public static void main(String[] args) {
            Semaphore semaphore =  new Semaphore(3);//3个停车位
            for (int i = 1; i <= 6; i++) {//六辆车争抢停车位
                new Thread(()->{
                    try {
                        semaphore.acquire();
                        System.out.println(Thread.currentThread().getName()+"抢到停车位");
                        TimeUnit.SECONDS.sleep(1);
                        System.out.println(Thread.currentThread().getName()+"离开停车位");
                    } catch (InterruptedException e) {
                    }finally {
                        semaphore.release();
                    }
                },String.valueOf("车"+i)).start();
            }
    }
}

 

posted @ 2022-06-19 23:19  禁止摆烂  阅读(84)  评论(0)    收藏  举报