【JavaSE】Java基础语法(三十八):并发工具类

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

1. Hashtable

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

==代码实现 ==:

import java.util.HashMap;
import java.util.Hashtable;
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
  }
}

2. ConcurrentHashMap基本使用

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

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

  • 体系结构 :

8ee196ddbab64d0fb5b3d2704c550555.png

  • 总结 :
    1 ,HashMap是线程不安全的。多线程环境下会有数据安全问题
    2 ,Hashtable是线程安全的,但是会将整张表锁起来,效率低下
    3,ConcurrentHashMap也是线程安全的,效率较高。 在JDK7和JDK8中,底层原理不一样。

代码实现

import java.util.Hashtable;
import java.util.concurrent.ConcurrentHashMap;
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
  }
}

3. ConcurrentHashMap1.7原理


6ef0aa0c36c14f0b9ffc03392941956d.png

4. ConcurrentHashMap1.8原理

8d39ba8cd7914f7c872ac0c03f625c6e.png

总结 :

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

时候创建哈希表

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

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

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

成链表。

5,当链表的长度大于等于8时,自动转换成红黑树6,以链表或者红黑树头结点为锁对象,配合悲观

锁保证多线程操作集合时数据的安全性。

5. CountDownLatch

  • CountDownLatch类 :

eb03149222a248c586b9357f5138423b.png

  • 使用场景
    让某一条线程等待其他线程执行完毕之后再执行
  • 代码实现
import java.util.concurrent.CountDownLatch;
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("妈妈在收拾碗筷");
  }
}

总结 :

  1. CountDownLatch(int count):参数写等待线程的数量。并定义了一个计数器。
  2. await():让线程等待,当计数器为0时,会唤醒等待的线程
  3. countDown(): 线程执行完毕时调用,会将计数器-1。

6. Semaphore

  • 使用场景 :
    可以控制访问特定资源的线程数量。
  • 实现步骤 :
    1,需要有人管理这个通道
    2,当有车进来了,发通行许可证
    3,当车出去了,收回通行许可证
    4,如果通行许可证发完了,那么其他车辆只能等着

代码实现 :

import java.util.concurrent.Semaphore;
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();
  }
  }
}

相关文章
|
1天前
|
存储 Java 容器
Java语言中的基础语法详解
Java语言中的基础语法详解
|
1天前
|
缓存 安全 Java
Java的线程池与并发工具类技术性文章
Java的线程池与并发工具类技术性文章
6 0
|
2天前
|
存储 Java 开发者
Java的语法基础
Java的语法基础
|
2天前
|
存储 移动开发 Java
Java的基本语法和语句
Java的基本语法和语句
|
2天前
|
存储 Java 索引
Java的基本语法格式详解
Java的基本语法格式详解
|
4天前
|
缓存 安全 Java
Java 语法 (杂七杂八的知识)
Java 语法 (杂七杂八的知识)
31 9
|
6天前
|
安全 Java 开发者
探索Java中的多线程编程与并发控制
多线程编程是Java编程中不可或缺的一部分,它允许程序同时执行多个任务,从而显著提高程序的整体性能。然而,多线程编程也带来了诸如数据不一致、死锁等并发问题。本文将深入探讨Java中的多线程编程技术,包括线程的创建、同步与通信,并介绍几种常用的并发控制策略,旨在帮助读者更好地理解并发编程的复杂性和挑战,并学会如何编写高效、安全的并发程序。
|
7天前
|
存储 Java 开发者
Java语言基础语法详解
Java语言基础语法详解
|
8天前
|
缓存 安全 Java
JAVA多线程编程与并发控制
```markdown Java多线程编程与并发控制关键点:1) 通过Thread或Runnable创建线程,管理线程状态;2) 使用synchronized关键字和ReentrantLock实现线程同步,防止数据竞争;3) 利用线程池(如Executors)优化资源管理,提高系统效率。并发控制需注意线程安全,避免死锁,确保程序正确稳定。 ```
|
1天前
|
存储 安全 Java
Java语言中的多线程编程技术深入解析
Java语言中的多线程编程技术深入解析