JUC并发编程--- 四个常用类

Posted 小样5411

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC并发编程--- 四个常用类相关的知识,希望对你有一定的参考价值。

前言

四个常用类
CountDownLatch—减法计数器
CyclicBarrier—参数达到就执行Runnable接口实现
Semaphore—并发限流
ReadWriteLock—读写锁

别急,现在分别用例子解释这四个类的用法

一、CountDownLatch

两个重要方法:countDown()和await()

这是一仿最后一个放学的同学关门案例,CountDownLatch作用就是用countDown()数量-1,await()等待计数器归零,然后向下执行,于是所有同学先走完,归零后,await()发现已经归零,于是向下执行Close Door

package com.yx.oftenClass;

import java.util.concurrent.CountDownLatch;

//减法计数器
public class countDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"->Go Out");
                countDownLatch.countDown();//数量-1,这是它第一个重点方法
            },String.valueOf(i)).start();
        }

        countDownLatch.await();//等待计数器归零,然后向下执行
        System.out.println("Close Door");
    }
}

效果
在这里插入图片描述
等所有结束后,执行await()下面的代码

二、CyclicBarrier

CyclicBarrier构造函数有两个参数
在这里插入图片描述
一个是表示数量到达parties,就执行线程实现,这里可以以集齐7张不同卡片兑换礼品案例

package com.yx.oftenClass;

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

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        /**
         * 集齐7张卡片,拿到棒棒糖,达到了参数就会执行一个线程
         */
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("大棒棒糖一个");
        });

        for (int i = 1; i <= 7; i++) {
            final int temp = i;
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"已经集齐第"+temp+"张卡片");
                try {
                    cyclicBarrier.await();//等待是否满7个
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}

在这里插入图片描述

三、Semaphore

Semaphore并发限流作用,比如抢车位,设置只有3个车位,那么必须要有车位才能抢,没有就只能等释放。

package com.yx.oftenClass;

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 = 0; i < 6; i++) {
            new Thread(()->{
                //获取
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"抢到车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName()+"离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();//释放
                }
            },String.valueOf(i)).start();
        }
    }
}

在这里插入图片描述

四、ReadWriteLock读写锁

读写锁就是在写的过程中只能有一个线程占用,读可以由多个线程读

package com.yx.oftenClass;

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.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 独占锁(写锁):一次只能被一个线程占有
 * 共享锁(读锁):多个线程可以同时占有
 * 没有加锁的自定义写入是乱的,不能保证写入是只有一个线程
 */
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCache myCache = new MyCache();
        MyCacheLock myCacheLock = new MyCacheLock();
        //写入
        for (int i = 0; i < 5; i++) {
            final int temp=i;
            new Thread(()->{
                myCacheLock.put(temp+"",temp+"");
            },String.valueOf(i)).start();
        }
        //读取
        for (int i = 0; i < 5; i++) {
            final int temp=i;
            new Thread(()->{
                myCacheLock.get(temp+"");
            },String.valueOf(i)).start();
        }
    }
}
/**
 * 自定义缓存
 */
class MyCache{
    private volatile Map<String,Object> map = new HashMap<>();
    //存,写
    public void put(String key,Object value){
        System.out.println(Thread.currentThread().getName()+"写入"+key);
        map.put(key,value);
        System.out.println(Thread.currentThread().getName()+"写入OK");
    }
    //取,读
    public void get(String key){
        System.out.println(Thread.currentThread().getName()+"读取"+key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName()+"读取OK");
    }
}
//加锁
class MyCacheLock{
    private volatile Map<String,Object> map = new HashMap<>();
    //读写锁,更加细粒度控制
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    //存,写,独占
    public void put(String key,Object value){
        readWriteLock.writeLock().lock();
        try {
            //业务
            System.out.println(Thread.currentThread().getName()+"写入"+key);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+"写入OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }
    //取,读,共享
    public void get(String key){
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"读取"+key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName()+"读取OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }
}

一开始用自己自定义的锁,然后用ReadWriteLock读写锁,对比可以看出写入操作就一个线程执行,执行完下一个才执行
在这里插入图片描述

以上是关于JUC并发编程--- 四个常用类的主要内容,如果未能解决你的问题,请参考以下文章

JUC并发编程--AQS

JUC并发编程 -- 线程常用方法概述 & start() vs run()

并发编程-阻塞队列&JUC常用工具

JUC 常用 4 大并发工具类

JUC 中 4 个常用的并发工具类

并发与多线程——常用工具类(JUC)