当前位置:   article > 正文

多线程(六):并发容器类讲解_java多线程中的volunteer

java多线程中的volunteer

目录

并发工具类

并发工具类-Hashtable

并发工具类-ConcurrentHashMap基本使用

并发工具类-ConcurrentHashMap1.7原理

并发工具类-ConcurrentHashMap1.8原理

并发工具类-CountDownLatch

并发工具类-Semaphore


并发工具类

并发工具类-Hashtable

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

代码实现 :

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

并发工具类-ConcurrentHashMap基本使用

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

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

体系结构 :

总结 :

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

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

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

代码实现 

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

并发工具类-ConcurrentHashMap1.7原理

并发工具类-ConcurrentHashMap1.8原理

总结 :

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

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

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

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

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

并发工具类-CountDownLatch

CountDownLatch类 :

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

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

代码实现 :

  1. import java.util.concurrent.CountDownLatch;
  2. /**
  3. * @author wangyy
  4. * @Date 2021-06-25
  5. */
  6. public class ChileThread1 extends Thread {
  7. private CountDownLatch countDownLatch;
  8. public ChileThread1(CountDownLatch countDownLatch) {
  9. this.countDownLatch = countDownLatch;
  10. }
  11. @Override
  12. public void run() {
  13. //1.吃饺子
  14. for (int i = 1; i <= 10; i++) {
  15. System.out.println(getName() + "在吃第" + i + "个饺子");
  16. }
  17. //2.吃完说一声
  18. //每一次countDown方法的时候,就让计数器-1
  19. countDownLatch.countDown();
  20. }
  21. }
  22. import java.util.concurrent.CountDownLatch;
  23. public class ChileThread2 extends Thread {
  24. private CountDownLatch countDownLatch;
  25. public ChileThread2(CountDownLatch countDownLatch) {
  26. this.countDownLatch = countDownLatch;
  27. }
  28. @Override
  29. public void run() {
  30. //1.吃饺子
  31. for (int i = 1; i <= 15; i++) {
  32. System.out.println(getName() + "在吃第" + i + "个饺子");
  33. }
  34. //2.吃完说一声
  35. //每一次countDown方法的时候,就让计数器-1
  36. countDownLatch.countDown();
  37. }
  38. }
  39. import java.util.concurrent.CountDownLatch;
  40. public class ChileThread3 extends Thread {
  41. private CountDownLatch countDownLatch;
  42. public ChileThread3(CountDownLatch countDownLatch) {
  43. this.countDownLatch = countDownLatch;
  44. }
  45. @Override
  46. public void run() {
  47. //1.吃饺子
  48. for (int i = 1; i <= 20; i++) {
  49. System.out.println(getName() + "在吃第" + i + "个饺子");
  50. }
  51. //2.吃完说一声
  52. //每一次countDown方法的时候,就让计数器-1
  53. countDownLatch.countDown();
  54. }
  55. }
  56. import java.util.concurrent.CountDownLatch;
  57. public class MotherThread extends Thread {
  58. private CountDownLatch countDownLatch;
  59. public MotherThread(CountDownLatch countDownLatch) {
  60. this.countDownLatch = countDownLatch;
  61. }
  62. @Override
  63. public void run() {
  64. //1.等待
  65. try {
  66. //当计数器变成0的时候,会自动唤醒这里等待的线程。
  67. countDownLatch.await();
  68. } catch (InterruptedException e) {
  69. e.printStackTrace();
  70. }
  71. //2.收拾碗筷
  72. System.out.println("妈妈在收拾碗筷");
  73. }
  74. }
  75. import java.util.concurrent.CountDownLatch;
  76. public class MyCountDownLatchDemo {
  77. public static void main(String[] args) {
  78. //1.创建CountDownLatch的对象,需要传递给四个线程。
  79. //在底层就定义了一个计数器,此时计数器的值就是3
  80. CountDownLatch countDownLatch = new CountDownLatch(3);
  81. //2.创建四个线程对象并开启他们。
  82. MotherThread motherThread = new MotherThread(countDownLatch);
  83. motherThread.start();
  84. ChileThread1 t1 = new ChileThread1(countDownLatch);
  85. t1.setName("小明");
  86. ChileThread2 t2 = new ChileThread2(countDownLatch);
  87. t2.setName("小红");
  88. ChileThread3 t3 = new ChileThread3(countDownLatch);
  89. t3.setName("小刚");
  90. t1.start();
  91. t2.start();
  92. t3.start();
  93. }
  94. }

总结 :

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

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

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

并发工具类-Semaphore

使用场景 :

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

实现步骤 :

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

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

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

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

代码实现 :

  1. import java.util.concurrent.Semaphore;
  2. /**
  3. * @author wangyy
  4. * @Date 2021-06-25
  5. */
  6. public class MyRunnable implements Runnable {
  7. //1.获得管理员对象,
  8. private Semaphore semaphore = new Semaphore(2);
  9. @Override
  10. public void run() {
  11. //2.获得通行证
  12. try {
  13. semaphore.acquire();
  14. //3.开始行驶
  15. System.out.println("获得了通行证开始行驶");
  16. Thread.sleep(2000);
  17. System.out.println("归还通行证");
  18. //4.归还通行证
  19. semaphore.release();
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }
  25. public class MySemaphoreDemo {
  26. public static void main(String[] args) {
  27. MyRunnable mr = new MyRunnable();
  28. for (int i = 0; i < 100; i++) {
  29. new Thread(mr).start();
  30. }
  31. }
  32. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/149080
推荐阅读
相关标签
  

闽ICP备14008679号