【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中的线程同步与并发控制
【5月更文挑战第18天】随着计算机技术的不断发展,多核处理器的普及使得多线程编程成为提高程序性能的关键。在Java中,线程是实现并发的一种重要手段。然而,线程的并发执行可能导致数据不一致、死锁等问题。本文将深入探讨Java中线程同步的方法和技巧,以及如何避免常见的并发问题,从而提高程序的性能和稳定性。
|
1天前
|
安全 Java 容器
Java一分钟之-并发编程:并发容器(ConcurrentHashMap, CopyOnWriteArrayList)
【5月更文挑战第18天】本文探讨了Java并发编程中的`ConcurrentHashMap`和`CopyOnWriteArrayList`,两者为多线程数据共享提供高效、线程安全的解决方案。`ConcurrentHashMap`采用分段锁策略,而`CopyOnWriteArrayList`适合读多写少的场景。注意,`ConcurrentHashMap`的`forEach`需避免手动同步,且并发修改时可能导致`ConcurrentModificationException`。`CopyOnWriteArrayList`在写操作时会复制数组。理解和正确使用这些特性是优化并发性能的关键。
7 1
|
1天前
|
安全 Java 容器
Java一分钟之-高级集合框架:并发集合(Collections.synchronizedXXX)
【5月更文挑战第18天】Java集合框架的`Collections.synchronizedXXX`方法可将普通集合转为线程安全,但使用时需注意常见问题和易错点。错误的同步范围(仅同步单个操作而非迭代)可能导致并发修改异常;错误地同步整个集合类可能引起死锁;并发遍历和修改集合需使用`Iterator`避免`ConcurrentModificationException`。示例代码展示了正确使用同步集合的方法。在复杂并发场景下,推荐使用`java.util.concurrent`包中的并发集合以提高性能。
9 3
|
4天前
|
小程序 Java 容器
03|Java基础语法:讲解标识符、关键字、变量、数据类型、运算符、控制语句(条件分支、循环)
03|Java基础语法:讲解标识符、关键字、变量、数据类型、运算符、控制语句(条件分支、循环)
10 0
|
4天前
|
Java
深入浅出Java基础语法:标识符、关键字、变量、数据类型、运算符与控制语句
深入浅出Java基础语法:标识符、关键字、变量、数据类型、运算符与控制语句
8 0
|
4天前
|
存储 安全 算法
掌握Java并发编程:Lock、Condition与并发集合
掌握Java并发编程:Lock、Condition与并发集合
14 0
|
4天前
|
Java
Java并发Futures和Callables类
Java程序`TestThread`演示了如何在多线程环境中使用`Futures`和`Callables`。它创建了一个单线程`ExecutorService`,然后提交两个`FactorialService`任务,分别计算10和20的阶乘。每个任务返回一个`Future`对象,通过`get`方法获取结果,该方法会阻塞直到计算完成。计算过程中模拟延迟以展示异步执行。最终,打印出10!和20!的结果。
24 10
|
4天前
|
安全 Java
Java中的并发编程:理解并发性与线程安全
Java作为一种广泛应用的编程语言,在并发编程方面具有显著的优势和特点。本文将探讨Java中的并发编程概念,重点关注并发性与线程安全,并提供一些实用的技巧和建议,帮助开发人员更好地理解和应用Java中的并发机制。
|
存储 安全 Java
Java8语法最佳实践-什么是对象(下)
计算机革命起源机器。编程语言就像是那台机器。它不仅是我们思维放大的工具与另一种表达媒介,更像是我们思想的一部分。语言的灵感来自其他形式的表达,如写作,绘画,雕塑,动画和电影制作。编程语言就是创建应用程序的思想结构。
84 0
|
存储 算法 Java
Java8语法最佳实践-什么是对象(上)
计算机革命起源机器。编程语言就像是那台机器。它不仅是我们思维放大的工具与另一种表达媒介,更像是我们思想的一部分。语言的灵感来自其他形式的表达,如写作,绘画,雕塑,动画和电影制作。编程语言就是创建应用程序的思想结构。
143 0
Java8语法最佳实践-什么是对象(上)