• Java之并发工具类的详细解析


    3. 并发工具类

    3.1 并发工具类-Hashtable

    Hashtable出现的原因 :集合类中HashMap是比较常用的集合对象,但是HashMap是线程不安全的(多线程环境下可能会存在问题)。为了保证数据的安全性我们可以使用Hashtable,但是Hashtable的效率低下。

    代码实现 :

    1. package com.itheima.mymap;
    2. import java.util.HashMap;
    3. import java.util.Hashtable;
    4. public class MyHashtableDemo {
    5.    public static void main(String[] args) throws InterruptedException {
    6.        Hashtable hm = new Hashtable<>();
    7.        Thread t1 = new Thread(() -> {
    8.            for (int i = 0; i < 25; i++) {
    9.                hm.put(i + "", i + "");
    10.           }
    11.       });
    12.        Thread t2 = new Thread(() -> {
    13.            for (int i = 25; i < 51; i++) {
    14.                hm.put(i + "", i + "");
    15.           }
    16.       });
    17.        t1.start();
    18.        t2.start();
    19.        System.out.println("----------------------------");
    20.        //为了t1和t2能把数据全部添加完毕
    21.        Thread.sleep(1000);
    22.        //0-0 1-1 ..... 50- 50
    23.        for (int i = 0; i < 51; i++) {
    24.            System.out.println(hm.get(i + ""));
    25.       }//0 1 2 3 .... 50
    26.   }
    27. }

    3.2 并发工具类-ConcurrentHashMap基本使用

    ConcurrentHashMap出现的原因 : 在集合类中HashMap是比较常用的集合对象,但是HashMap是线程不安全的(多线程环境下可能会存在问题)。为了保证数据的安全性我们可以使用Hashtable,但是Hashtable的效率低下。

    基于以上两个原因我们可以使用JDK1.5以后所提供的ConcurrentHashMap。

    体系结构 :

    总结 :

    1 ,HashMap是线程不安全的。多线程环境下会有数据安全问题

    2 ,Hashtable是线程安全的,但是会将整张表锁起来,效率低下

    3,ConcurrentHashMap也是线程安全的,效率较高。 在JDK7和JDK8中,底层原理不一样。

    代码实现 :

    1. package com.itheima.mymap;
    2. import java.util.Hashtable;
    3. import java.util.concurrent.ConcurrentHashMap;
    4. public class MyConcurrentHashMapDemo {
    5.    public static void main(String[] args) throws InterruptedException {
    6.        ConcurrentHashMap hm = new ConcurrentHashMap<>(100);
    7.        Thread t1 = new Thread(() -> {
    8.            for (int i = 0; i < 25; i++) {
    9.                hm.put(i + "", i + "");
    10.           }
    11.       });
    12.        Thread t2 = new Thread(() -> {
    13.            for (int i = 25; i < 51; i++) {
    14.                hm.put(i + "", i + "");
    15.           }
    16.       });
    17.        t1.start();
    18.        t2.start();
    19.        System.out.println("----------------------------");
    20.        //为了t1和t2能把数据全部添加完毕
    21.        Thread.sleep(1000);
    22.        //0-0 1-1 ..... 50- 50
    23.        for (int i = 0; i < 51; i++) {
    24.            System.out.println(hm.get(i + ""));
    25.       }//0 1 2 3 .... 50
    26.   }
    27. }

    3.3 并发工具类-ConcurrentHashMap1.7原理

    3.4 并发工具类-ConcurrentHashMap1.8原理

    总结 :

    1,如果使用空参构造创建ConcurrentHashMap对象,则什么事情都不做。 在第一次添加元素的时候创建哈希表

    2,计算当前元素应存入的索引。

    3,如果该索引位置为null,则利用cas算法,将本结点添加到数组中。

    4,如果该索引位置不为null,则利用volatile关键字获得当前位置最新的结点地址,挂在他下面,变成链表。

    5,当链表的长度大于等于8时,自动转换成红黑树6,以链表或者红黑树头结点为锁对象,配合悲观锁保证多线程操作集合时数据的安全性

    3.5 并发工具类-CountDownLatch

    CountDownLatch类 :

    方法解释
    public CountDownLatch(int count)参数传递线程数,表示等待线程数量
    public void await()让线程等待
    public void countDown()当前线程执行完毕

    使用场景: 让某一条线程等待其他线程执行完毕之后再执行

    代码实现 :

    1. package com.itheima.mycountdownlatch;
    2. import java.util.concurrent.CountDownLatch;
    3. public class ChileThread1 extends Thread {
    4.    private CountDownLatch countDownLatch;
    5.    public ChileThread1(CountDownLatch countDownLatch) {
    6.        this.countDownLatch = countDownLatch;
    7.   }
    8.    @Override
    9.    public void run() {
    10.        //1.吃饺子
    11.        for (int i = 1; i <= 10; i++) {
    12.            System.out.println(getName() + "在吃第" + i + "个饺子");
    13.       }
    14.        //2.吃完说一声
    15.        //每一次countDown方法的时候,就让计数器-1
    16.        countDownLatch.countDown();
    17.   }
    18. }
    1. package com.itheima.mycountdownlatch;
    2. import java.util.concurrent.CountDownLatch;
    3. public class ChileThread2 extends Thread {
    4.    private CountDownLatch countDownLatch;
    5.    public ChileThread2(CountDownLatch countDownLatch) {
    6.        this.countDownLatch = countDownLatch;
    7.   }
    8.    @Override
    9.    public void run() {
    10.        //1.吃饺子
    11.        for (int i = 1; i <= 15; i++) {
    12.            System.out.println(getName() + "在吃第" + i + "个饺子");
    13.       }
    14.        //2.吃完说一声
    15.        //每一次countDown方法的时候,就让计数器-1
    16.        countDownLatch.countDown();
    17.   }
    18. }
    1. package com.itheima.mycountdownlatch;
    2. import java.util.concurrent.CountDownLatch;
    3. public class ChileThread3 extends Thread {
    4.    private CountDownLatch countDownLatch;
    5.    public ChileThread3(CountDownLatch countDownLatch) {
    6.        this.countDownLatch = countDownLatch;
    7.   }
    8.    @Override
    9.    public void run() {
    10.        //1.吃饺子
    11.        for (int i = 1; i <= 20; i++) {
    12.            System.out.println(getName() + "在吃第" + i + "个饺子");
    13.       }
    14.        //2.吃完说一声
    15.        //每一次countDown方法的时候,就让计数器-1
    16.        countDownLatch.countDown();
    17.   }
    18. }
    1. package com.itheima.mycountdownlatch;
    2. import java.util.concurrent.CountDownLatch;
    3. public class MotherThread extends Thread {
    4.    private CountDownLatch countDownLatch;
    5.    public MotherThread(CountDownLatch countDownLatch) {
    6.        this.countDownLatch = countDownLatch;
    7.   }
    8.    @Override
    9.    public void run() {
    10.        //1.等待
    11.        try {
    12.            //当计数器变成0的时候,会自动唤醒这里等待的线程。
    13.            countDownLatch.await();
    14.       } catch (InterruptedException e) {
    15.            e.printStackTrace();
    16.       }
    17.        //2.收拾碗筷
    18.        System.out.println("妈妈在收拾碗筷");
    19.   }
    20. }
    1. package com.itheima.mycountdownlatch;
    2. import java.util.concurrent.CountDownLatch;
    3. public class MyCountDownLatchDemo {
    4.    public static void main(String[] args) {
    5.        //1.创建CountDownLatch的对象,需要传递给四个线程。
    6.        //在底层就定义了一个计数器,此时计数器的值就是3
    7.        CountDownLatch countDownLatch = new CountDownLatch(3);
    8.        //2.创建四个线程对象并开启他们。
    9.        MotherThread motherThread = new MotherThread(countDownLatch);
    10.        motherThread.start();
    11.        ChileThread1 t1 = new ChileThread1(countDownLatch);
    12.        t1.setName("小明");
    13.        ChileThread2 t2 = new ChileThread2(countDownLatch);
    14.        t2.setName("小红");
    15.        ChileThread3 t3 = new ChileThread3(countDownLatch);
    16.        t3.setName("小刚");
    17.        t1.start();
    18.        t2.start();
    19.        t3.start();
    20.   }
    21. }

    总结 :

    1. CountDownLatch(int count):参数写等待线程的数量。并定义了一个计数器。

    2. await():让线程等待,当计数器为0时,会唤醒等待的线程

    3. countDown(): 线程执行完毕时调用,会将计数器-1。

    3.6 并发工具类-Semaphore

    使用场景 :

    可以控制访问特定资源的线程数量。

    实现步骤 :

    1,需要有人管理这个通道

    2,当有车进来了,发通行许可证

    3,当车出去了,收回通行许可证

    4,如果通行许可证发完了,那么其他车辆只能等着

    代码实现 :

    1. package com.itheima.mysemaphore;
    2. import java.util.concurrent.Semaphore;
    3. public class MyRunnable implements Runnable {
    4.    //1.获得管理员对象,
    5.    private Semaphore semaphore = new Semaphore(2);
    6.    @Override
    7.    public void run() {
    8.        //2.获得通行证
    9.        try {
    10.            semaphore.acquire();
    11.            //3.开始行驶
    12.            System.out.println("获得了通行证开始行驶");
    13.            Thread.sleep(2000);
    14.            System.out.println("归还通行证");
    15.            //4.归还通行证
    16.            semaphore.release();
    17.       } catch (InterruptedException e) {
    18.            e.printStackTrace();
    19.       }
    20.   }
    21. }
    1. package com.itheima.mysemaphore;
    2. public class MySemaphoreDemo {
    3.    public static void main(String[] args) {
    4.        MyRunnable mr = new MyRunnable();
    5.        for (int i = 0; i < 100; i++) {
    6.            new Thread(mr).start();
    7.       }
    8.   }
    9. }
  • 相关阅读:
    【MySQL】基础实战篇(3)—九大储存引擎详解
    【Mindspore】GeneratorDataset 中source data 含有dict 应该如何处理
    binary_cross_entropy和binary_cross_entropy_with_logits的区别
    EMR重磅发布智能运维诊断系统(EMR Doctor)——开源大数据平台运维利器
    网格化覆盖·智能化管控·数字化通行|公租房智能门锁有一套!
    如何快速给图标包命名
    JS中的filter、map、reduce
    hexdump 命令 -e 选项
    人工智能介绍
    猿创征文|机器学习实战(9)——降维
  • 原文地址:https://blog.csdn.net/qq_69748833/article/details/133561237