谈谈java的concurrent用法

Java Concurrent 包使用攻略

Java Concurrent 包提供了一系列并发编程的工具类和接口,用于简化多线程编程、提高并发性能和优化资源利用。在编写高性能的、并发的、安全的多线程应用程序时,Java Concurrent 包是一项必不可少的技术。本文将详细介绍 Java Concurrent 包的常用用法。

基础概念

线程安全性

多线程并发编程中最重要的概念是线程安全性。线程安全性指的是多线程环境下,共享资源能正确、高效地被多个线程同时访问,而不出现数据竞争、内存泄漏等问题。在 Java 中,线程安全性是由以下几个方面保证的:

  • 原子性:对于变量的单个读取和写入操作是原子性的,不可被其他线程干扰。
  • 可见性:对于变量修改的结果,对其他线程是可见的。
  • 有序性:操作的指令执行顺序是有序的,不会因为指令排序等问题出现错误。

内存模型

Java 中的内存模型是描述多线程并发编程中的内存交互的抽象规范。在 Java 内存模型中,每个线程都有自己独立的工作内存,而所有线程共享一个主内存。线程从主内存读取变量到本地内存中进行操作,写回到主内存时,再将本地内存中的操作结果写回。在多核处理器中,不同线程可能在不同的 CPU 上执行。因此,在多线程编程中,需要关注线程之间的同步和内存可见性问题,以避免出现数据竞争和线程间通信问题等。

Concurrent 包常用类和接口

Java Concurrent 包中包含了大量解决并发问题的类和接口,其中比较常用的有以下几个:

Lock 接口

Lock 接口提供了与关键字synchronized类似的互斥实现,但它能够更加灵活地控制线程之间的协作和同步,常用实现类有 ReentrantLock 和 ReentrantReadWriteLock。使用 Lock 接口需要手动显示释放锁,需要搭配 try-finally 或 try-with-resources 以确保锁被正确释放。

Lock lock = new ReentrantLock();
lock.lock();
try {
    // 进行加锁操作的线程代码
} finally {
    lock.unlock();
}

synchronized 关键字

synchronized 关键字用于同步访问共享资源,在 Java 中是一个基础的同步机制,使用简单。关键字 synchronized 将对象作为锁(monitor)来控制多线程之间的协作和同步。

synchronized (lock) {
    //访问共享资源的线程代码
}

Executor 和 ExecutorService 接口

Executor 和 ExecutorService 接口是用于管理线程池的核心接口。Executor 接口负责管理线程的创建、销毁和运行,ExecutorService 接口是 Executor 接口的子类,扩展了线程池的一些功能,比如允许提交 Callable 和 Runnable 任务、设置执行延迟、取消任务等。

ExecutorService executor = Executors.newFixedThreadPool(10);

CountDownLatch 类

CountDownLatch 类是一个倒计时计数器,可以通过计数完成等待线程执行的任务。这个计数器不能被重置,当计数到达零时,所有等待线程就都会被释放。在这之前将会一直阻塞线程,通过 CountDownLatch 可以协调多个线程的并发操作。

CountDownLatch latch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
    executor.submit(() -> {
        // 线程任务的执行代码
        latch.countDown();
    });
}
latch.await();
// 所有子线程任务都执行完毕的后续代码

CyclicBarrier 类

CyclicBarrier 类可以协调多个线程的并发操作,当多个线程都执行到栅栏点,才会继续执行。CyclicBarrier 可以重复使用,重用后设置的栅栏点会重置。

CyclicBarrier barrier = new CyclicBarrier(10);
for (int i = 0; i < 10; i++) {
    executor.submit(() -> {
        // 线程任务的执行代码
        barrier.await();
    });
}
// 所有子线程任务都执行完毕的后续代码

示例说明

示例1:计算线程

需求:编写一个利用多线程计算数组元素和的程序,要求多线程共同计算,最后返回结果。

public class Calculator implements Callable<Integer> {

    private final int[] numbers;

    public Calculator(int[] numbers) {
        this.numbers = numbers;
    }

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int number : numbers) {
            sum += number;
        }
        return sum;
    }
}

使用 Callable 接口实现计算任务,并返回任务的结果。

ExecutorService executor = Executors.newFixedThreadPool(10);
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<Callable<Integer>> tasks = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    tasks.add(new Calculator(numbers));
}
List<Future<Integer>> results = executor.invokeAll(tasks);
int sum = 0;
for (Future<Integer> future : results) {
    sum += future.get();
}
System.out.println("Total sum: " + sum);

将任务放到线程池中执行后,再从 Future 中获取所有任务结果并计算总和。最终输出:Total sum: 55。

示例2:乘客、司机案例

需求:模拟多个乘客拼车,司机只有在车上人满发车,或时间到了才会出发。

public class Car {
    private final int seats = 5;
    private final CountDownLatch count = new CountDownLatch(seats);

    public void addPassenger() throws InterruptedException {
        count.countDown();
    }

    public void start() {
        try {
            count.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Car is full. Start!");
    }
}

public class Passenger implements Runnable {

    private final Car car;

    public Passenger(Car car) {
        this.car = car;
    }

    @Override
    public void run() {
        try {
            car.addPassenger();
            System.out.println("Passenger added. Current number: " + (car.seats - (int)car.count.getCount()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Driver implements Runnable {

    private final Car car;

    public Driver(Car car) {
        this.car = car;
    }

    @Override
    public void run() {
        car.start();
    }
}

public class Simulator {

    public static void main(String[] args) {
        Car car = new Car();
        ExecutorService executor = Executors.newFixedThreadPool(6);
        for (int i = 0; i < car.seats - 1; i++) {
            executor.submit(new Passenger(car));
        }
        executor.submit(new Driver(car));
        executor.shutdown();
    }
}

创建一个 Car 类来表示车,有座位数限制和等待候车的旅客计数器。乘客和司机都是一个 Runnable 类,一个 Runnable 对象负责一个线程。通过 CountDownLatch 来实现线程之间的协调。每次加入一个旅客时,让计数器减一,当计数器减为零时,司机就会发车。

总结

Java Concurrent 包提供了丰富的多线程 API,包括锁、线程池、同步工具、线程安全容器等,可以极大地简化多线程编程、提高性能、优化资源利用。但是并发编程本身存在复杂性、难度以及易出现不可预见的问题,需要在开发中加以注意和处理。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:谈谈java的concurrent用法 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • MySQL 数据库如何解决高并发问题

    MySQL 数据库在高并发场景下有多种解决方法,下面我将介绍其中的一些方法。 1. 优化 SQL 语句 首先,要优化 SQL 语句以提高查询速度和降低系统的负载。 1.1 索引 索引是提高查询速度的关键。在创建表时,需要考虑哪些字段需要作为索引来优化查询。不过,索引的过多也会影响写入性能,因此需要根据实际情况来选择适当的索引。 1.2 避免使用 SELECT…

    多线程 2023年5月16日
    00
  • Java多线程ThreadPoolExecutor详解

    Java多线程ThreadPoolExecutor详解 ThreadPoolExecutor 是 Java 中常用的线程池实现类,通过线程池可以更好地使用资源,提高程序性能。本文将详细讲解 ThreadPoolExecutor 的使用,包括线程池的创建、使用和销毁等方面。 线程池的创建 线程池是通过 ThreadPoolExecutor 类创建的,构造方法有…

    多线程 2023年5月17日
    00
  • 浅谈Swoole并发编程的魅力

    浅谈Swoole并发编程的魅力 Swoole是一个基于PHP编写的异步、并行、高性能网络通信引擎。通过使用Swoole,我们可以轻松地实现并发编程,提高应用程序的性能和稳定性。 Swoole的优势 相较于传统的PHP,Swoole的优势主要体现在以下几个方面: 高性能:传统的PHP应用一般采用阻塞I/O模型,每个请求都需要单独开启一个线程或进程进行处理。而S…

    多线程 2023年5月16日
    00
  • 解决线程并发redisson使用遇到的坑

    解决线程并发redisson使用遇到的坑 在使用redisson进行多线程任务处理时,可能会遇到一些并发问题,例如资源冲突等问题。这里提供一些解决这些问题的方法: 使用分布式锁 在进行资源竞争时,可以使用redisson提供的分布式锁来保证资源的同步。Redisson提供了多种分布式锁,例如可重入锁、公平锁等,用户可以根据自己的具体需求选择适合的锁类型。 下…

    多线程 2023年5月16日
    00
  • 基于java 线程的几种状态(详解)

    基于 Java 线程的几种状态(详解) 在 Java 语言中,线程是一种非常重要的概念。线程可以被分为多个状态,在不同的状态下,线程的行为和特征是不同的。本文将详细介绍基于 Java 线程的几种状态,并通过两个示例来演示它们。 线程的状态 在 Java 中,线程有以下几种状态: 新建状态(New):线程尚未启动,处于新建状态。 运行状态(Running):线…

    多线程 2023年5月17日
    00
  • 服务器并发量估算公式和计算方法

    下面我将详细讲解“服务器并发量估算公式和计算方法”的完整攻略。 一、什么是服务器并发量 在讲解服务器并发量估算公式和计算方法之前,我们需要先了解一下什么是服务器并发量。 服务器并发量指的是在同一时刻访问服务器的用户数。例如,当1000个用户在同一时间请求一个页面,那么这个页面的服务器并发量就是1000。 二、服务器并发量估算公式 在计算服务器的并发量时,可以…

    多线程 2023年5月16日
    00
  • 浅谈Java多线程处理中Future的妙用(附源码)

    针对题目“浅谈Java多线程处理中Future的妙用(附源码)”,我将详细讲解Future在Java多线程编程中的应用以及实现方式。 什么是Future Future是Java中提供的一种异步编程的API,主要用于异步执行一个任务并返回一个结果。Future接口提供了一种获取异步任务执行完成结果的方法,它提供了一些方法,以使我们能够检查任务是否完成了、等待任…

    多线程 2023年5月17日
    00
  • 超详细讲解Linux C++多线程同步的方式

    下面就来详细讲解一下“超详细讲解Linux C++多线程同步的方式”的完整攻略。 如何实现多线程同步 在 C++ 程序中,线程之间的竞争条件是十分常见的一种情况,因此必须采取一些措施来避免这种情况的发生。以下是通过锁和条件变量来实现多线程同步的两种方式。 一、使用锁来实现多线程同步 锁可以帮助控制并发还原竞争。具体来说,当一个线程拥有锁时,任何其他线程都不能…

    多线程 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部