JUC三大辅助类(CountDownLatch、CyclicBarrier和Semaphore)、ReadWriteLock(读写锁)和BlockingQueue(阻塞队列)

JUC三大辅助类

一、CountDownLatch:减少计数方法

作用:让一些线程阻塞直到另一些线程完成一系列操作后才被唤醒。

提供的三个方法:

  1. new CountDownLatch(6);设置计数器为6个线程
  2. countDown();将计数器减1(调用countDown方法的线程不会阻塞)
  3. await();计数器的值>0,线程会阻塞,当计数器的值=0时,因await()方法阻塞的线程会被唤醒,继续执行
import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo
{
   public static void main(String[] args) throws InterruptedException
   {
         CountDownLatch countDownLatch = new CountDownLatch(6);
       
       for (int i = 1; i <=6; i++) //6个上自习的同学,各自离开教室的时间不一致
       {
          new Thread(() -> {
              System.out.println(Thread.currentThread().getName()+"\t 号同学离开教室");
			//线程调用countDown()方法会将计数器减1(调用countDown方法的线程不会阻塞)
              countDownLatch.countDown();
          }, String.valueOf(i)).start();
       }
       //线程调用await()方法时,这些线程会阻塞
       countDownLatch.await();
       //当计数器的值变为0时,因await()方法阻塞的线程会被唤醒,继续执行
       System.out.println(Thread.currentThread().getName()+"\t****** 班长关门走人,main线程是班长");          
   }
}

二、CyclicBarrier:循环栅栏方法

作用:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续执行。

提供的方法:

  1. new CyclicBarrier(int parties, Runnable barrierAction);构造方法中:需要类实现Runnable接口
  2. cyclicBarrier.await();同步点阻塞
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo
{
  private static final int NUMBER = 7;
  public static void main(String[] args)
  {
     //构造器:CyclicBarrier(int parties, Runnable barrierAction) 
     CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, ()->{System.out.println("*****集齐7颗龙珠就可以召唤神龙");}) ;

     for (int i = 1; i <= 7; i++) {
       new Thread(() -> {
          try {
            System.out.println(Thread.currentThread().getName()+"\t 星龙珠被收集 ");
            //阻塞点 awaitCurrent >= 7 ? openAwait() : await();
            cyclicBarrier.await();
          } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
          }
       }, String.valueOf(i)).start();
     }
  }
}

三、Semaphore:信号灯

作用:

  1. 用于多个共享资源的互斥使用
  2. 用于并发线程数的控制。

提供的方法:

  1. new Semaphore(3);//模拟3个资源,可申请使用可释放
  2. acquire();申请,当一个线程调用acquire()操作时,它要么通过,成功获取信号量(信号量减1),要么一直等下去,直到有线程释放信号量,或超时
  3. release();释放,使用在finally{}中,会将信号量的值加1,然后唤醒等待的线程
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreDemo
{
  public static void main(String[] args)
  {
     Semaphore semaphore = new Semaphore(3);//模拟3个停车位

     for (int i = 1; i <=6; i++) //模拟6部汽车
     {
       new Thread(() -> {
          try 
          {
            semaphore.acquire();//申请获取资源
            System.out.println(Thread.currentThread().getName()+"\t 抢到了车位");
            TimeUnit.SECONDS.sleep(new Random().nextInt(5));
            System.out.println(Thread.currentThread().getName()+"\t------- 离开");
          } catch (InterruptedException e) {
            e.printStackTrace();
          }finally {
            //释放资源信号量,唤醒等待线程
            semaphore.release();
          }
       }, String.valueOf(i)).start();
     }
  }
}

ReadWriteLock:读写锁

  • import java.util.concurrent.locks.*;三种锁:
    • Condition
    • Lock
    • ReadWriteLock

作用:多线程同时读写数据时会出现混乱,用读写锁将读写分开,让写分离,读读共享

提供方法:

  1. ReadWriteLock rwLock = new ReentrantReadWriteLock();实现类构造器
  2. 写锁writeLockrwLock.writeLock().lock();,在finally{}处解锁:rwLock.writeLock().unlock();
  3. 读锁readLockrwLock.readLock().lock();,在finally{}处解锁:rwLock.readLock().unlock();
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class MyCache {
    private volatile Map<String, Object> map = new HashMap<>();
    private ReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void put(String key, Object value) {
        rwLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t 正在写" + key);
            //暂停一会儿线程
            try {
                TimeUnit.MILLISECONDS.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "\t 写完了" + key);
            System.out.println();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    public Object get(String key) {
        rwLock.readLock().lock();
        Object result = null;
        try {
            System.out.println(Thread.currentThread().getName() + "\t 正在读" + key);
            try {
                TimeUnit.MILLISECONDS.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            result = map.get(key);
            System.out.println(Thread.currentThread().getName() + "\t 读完了" + result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rwLock.readLock().unlock();
        }
        return result;
    }
}

public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCache myCache = new MyCache();

        for (int i = 1; i <= 5; i++) {
            final int num = i;
            new Thread(() -> {
                myCache.put(num + "", num + "");
            }, String.valueOf(i)).start();
        }
        for (int i = 1; i <= 5; i++) {
            final int num = i;
            new Thread(() -> {
                myCache.get(num + "");
            }, String.valueOf(i)).start();
        }
    }
}

BlockingQueue:阻塞队列

当队列是空的,从队列中获取元素的操作将会被阻塞

当队列是满的,从队列中添加元素的操作将会被阻塞

  • Collection

    • Queue
      • BlockingQueue:阻塞队列
        • ArrayBlockingQueue:数组结构阻塞队列
        • LinkedBlockingQueue:链表结构阻塞队列(大小默认值为Integer.MAX_VALUE
        • SynchronousQueue:单元素阻塞队列
        • PriorityBlockingQueue:优先级排序无界阻塞队列
        • DelayQueue:优先级延迟无界阻塞队列
        • LinkedTransferQueue:链表无界阻塞队列
        • LinkedBlockingDeque:链表双向阻塞队列
  • BlockingQueue的方法:

    • 创建方法:BlockingQueue<String> Queue = new ArrayBlockingQueue<>(int initSize);
方法类型 抛出异常 返回特殊值 阻塞 超时
插入 boolean add(e) boolean offer(e) void put(e) boolean offer(e,timeout,timeunit)
删除 E remove() E poll() E take() boolean poll(e,timeout,timeunit)
检查 E element() E peek() / /
类型 说明
抛出异常 1. 当阻塞队列满时,再往队列里add插入元素
会抛IllegalStateException:Queue full
2. 当阻塞队列空时,再往队列里remove移除元素
会抛NoSuchElementException
特殊值 1. 插入方法,成功ture失败false
2. 删除方法,成功返回出队列的元素,队列里没有就返回null
一直阻塞 1. 当阻塞队列满时,生产者线程继续往队列里put元素,
队列会一直阻塞生产者线程直到put数据or响应中断退出
2. 当阻塞队列空时,消费者线程试图从队列里take元素,
队列会一直阻塞消费者线程直到队列可用
超时退出 当阻塞队列满时,队列会阻塞生产者线程一定时间,超过限时后生产者线程会退出
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章