赞
踩
目录
Hashtable出现的原因 : 在集合类中HashMap是比较常用的集合对象,但是HashMap是线程不安全的(多线程环境下可能会存在问题)。为了保证数据的安全性我们可以使用Hashtable,但是Hashtable的效率低下。
代码实现 :
- import java.util.HashMap;
- import java.util.Hashtable;
- /**
- * @author wangyy
- * @Date 2021-06-25
- */
- public class MyHashtableDemo {
- public static void main(String[] args) throws InterruptedException {
- Hashtable<String, String> hm = new Hashtable<>();
-
- Thread t1 = new Thread(() -> {
- for (int i = 0; i < 25; i++) {
- hm.put(i + "", i + "");
- }
- });
-
-
- Thread t2 = new Thread(() -> {
- for (int i = 25; i < 51; i++) {
- hm.put(i + "", i + "");
- }
- });
-
- t1.start();
- t2.start();
-
- System.out.println("----------------------------");
- //为了t1和t2能把数据全部添加完毕
- Thread.sleep(1000);
-
- //0-0 1-1 ..... 50- 50
-
- for (int i = 0; i < 51; i++) {
- System.out.println(hm.get(i + ""));
- }//0 1 2 3 .... 50
-
-
- }
- }
ConcurrentHashMap出现的原因 : 在集合类中HashMap是比较常用的集合对象,但是HashMap是线程不安全的(多线程环境下可能会存在问题)。为了保证数据的安全性我们可以使用Hashtable,但是Hashtable的效率低下。
基于以上两个原因我们可以使用JDK1.5以后所提供的ConcurrentHashMap。
体系结构 :
总结 :
1 ,HashMap是线程不安全的。多线程环境下会有数据安全问题
2 ,Hashtable是线程安全的,但是会将整张表锁起来,效率低下
3,ConcurrentHashMap也是线程安全的,效率较高。 在JDK7和JDK8中,底层原理不一样。
代码实现
- import java.util.Hashtable;
- import java.util.concurrent.ConcurrentHashMap;
- /**
- * @author wangyy
- * @Date 2021-06-25
- */
- public class MyConcurrentHashMapDemo {
- public static void main(String[] args) throws InterruptedException {
- ConcurrentHashMap<String, String> hm = new ConcurrentHashMap<>(100);
-
- Thread t1 = new Thread(() -> {
- for (int i = 0; i < 25; i++) {
- hm.put(i + "", i + "");
- }
- });
-
-
- Thread t2 = new Thread(() -> {
- for (int i = 25; i < 51; i++) {
- hm.put(i + "", i + "");
- }
- });
-
- t1.start();
- t2.start();
-
- System.out.println("----------------------------");
- //为了t1和t2能把数据全部添加完毕
- Thread.sleep(1000);
-
- //0-0 1-1 ..... 50- 50
-
- for (int i = 0; i < 51; i++) {
- System.out.println(hm.get(i + ""));
- }//0 1 2 3 .... 50
- }
- }
总结 :
1,如果使用空参构造创建ConcurrentHashMap对象,则什么事情都不做。 在第一次添加元素的时候创建哈希表
2,计算当前元素应存入的索引。
3,如果该索引位置为null,则利用cas算法,将本结点添加到数组中。
4,如果该索引位置不为null,则利用volatile关键字获得当前位置最新的结点地址,挂在他下面,变成链表。
5,当链表的长度大于等于8时,自动转换成红黑树6,以链表或者红黑树头结点为锁对象,配合悲观锁保证多线程操作集合时数据的安全性
CountDownLatch类 :
方法 | 解释 |
---|---|
public CountDownLatch(int count) | 参数传递线程数,表示等待线程数量 |
public void await() | 让线程等待 |
public void countDown() | 当前线程执行完毕 |
使用场景: 让某一条线程等待其他线程执行完毕之后再执行
代码实现 :
- import java.util.concurrent.CountDownLatch;
- /**
- * @author wangyy
- * @Date 2021-06-25
- */
- public class ChileThread1 extends Thread {
-
- private CountDownLatch countDownLatch;
- public ChileThread1(CountDownLatch countDownLatch) {
- this.countDownLatch = countDownLatch;
- }
-
- @Override
- public void run() {
- //1.吃饺子
- for (int i = 1; i <= 10; i++) {
- System.out.println(getName() + "在吃第" + i + "个饺子");
- }
- //2.吃完说一声
- //每一次countDown方法的时候,就让计数器-1
- countDownLatch.countDown();
- }
- }
-
-
- import java.util.concurrent.CountDownLatch;
-
- public class ChileThread2 extends Thread {
-
- private CountDownLatch countDownLatch;
- public ChileThread2(CountDownLatch countDownLatch) {
- this.countDownLatch = countDownLatch;
- }
- @Override
- public void run() {
- //1.吃饺子
- for (int i = 1; i <= 15; i++) {
- System.out.println(getName() + "在吃第" + i + "个饺子");
- }
- //2.吃完说一声
- //每一次countDown方法的时候,就让计数器-1
- countDownLatch.countDown();
- }
- }
-
-
- import java.util.concurrent.CountDownLatch;
-
- public class ChileThread3 extends Thread {
-
- private CountDownLatch countDownLatch;
- public ChileThread3(CountDownLatch countDownLatch) {
- this.countDownLatch = countDownLatch;
- }
- @Override
- public void run() {
- //1.吃饺子
- for (int i = 1; i <= 20; i++) {
- System.out.println(getName() + "在吃第" + i + "个饺子");
- }
- //2.吃完说一声
- //每一次countDown方法的时候,就让计数器-1
- countDownLatch.countDown();
- }
- }
-
-
- import java.util.concurrent.CountDownLatch;
-
- public class MotherThread extends Thread {
- private CountDownLatch countDownLatch;
- public MotherThread(CountDownLatch countDownLatch) {
- this.countDownLatch = countDownLatch;
- }
-
- @Override
- public void run() {
- //1.等待
- try {
- //当计数器变成0的时候,会自动唤醒这里等待的线程。
- countDownLatch.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- //2.收拾碗筷
- System.out.println("妈妈在收拾碗筷");
- }
- }
-
-
- import java.util.concurrent.CountDownLatch;
-
- public class MyCountDownLatchDemo {
- public static void main(String[] args) {
- //1.创建CountDownLatch的对象,需要传递给四个线程。
- //在底层就定义了一个计数器,此时计数器的值就是3
- CountDownLatch countDownLatch = new CountDownLatch(3);
- //2.创建四个线程对象并开启他们。
- MotherThread motherThread = new MotherThread(countDownLatch);
- motherThread.start();
-
- ChileThread1 t1 = new ChileThread1(countDownLatch);
- t1.setName("小明");
-
- ChileThread2 t2 = new ChileThread2(countDownLatch);
- t2.setName("小红");
-
- ChileThread3 t3 = new ChileThread3(countDownLatch);
- t3.setName("小刚");
-
- t1.start();
- t2.start();
- t3.start();
- }
- }
总结 :
1. CountDownLatch(int count):参数写等待线程的数量。并定义了一个计数器。
2. await():让线程等待,当计数器为0时,会唤醒等待的线程
3. countDown(): 线程执行完毕时调用,会将计数器-1。
使用场景 :
可以控制访问特定资源的线程数量。
实现步骤 :
1,需要有人管理这个通道
2,当有车进来了,发通行许可证
3,当车出去了,收回通行许可证
4,如果通行许可证发完了,那么其他车辆只能等着
代码实现 :
- import java.util.concurrent.Semaphore;
- /**
- * @author wangyy
- * @Date 2021-06-25
- */
- public class MyRunnable implements Runnable {
- //1.获得管理员对象,
- private Semaphore semaphore = new Semaphore(2);
- @Override
- public void run() {
- //2.获得通行证
- try {
- semaphore.acquire();
- //3.开始行驶
- System.out.println("获得了通行证开始行驶");
- Thread.sleep(2000);
- System.out.println("归还通行证");
- //4.归还通行证
- semaphore.release();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public class MySemaphoreDemo {
- public static void main(String[] args) {
- MyRunnable mr = new MyRunnable();
-
- for (int i = 0; i < 100; i++) {
- new Thread(mr).start();
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。