专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java性能优化神器,一文读懂Java并发工具

temp10 2025-03-04 13:56:43 java教程 6 ℃ 0 评论

概述

Java并发工具是Java平台的一部分,旨在简化多线程程序的设计和开发。

这些工具包括同步器(如ReentrantLock)、并发集合(如ConcurrentHashMap)、原子变量(如AtomicInteger)和任务调度器(如ScheduledExecutorService)。

Java性能优化神器,一文读懂Java并发工具

它们使开发者能够构建高效、可伸缩的应用程序,即使在多核处理器上也能良好运行。

基础概念

  1. 线程安全:当多个线程尝试同时访问某个资源时,确保一致性和完整性的一种属性。
  2. 同步器:一种机制,用于协调线程之间的协作。
  3. 并发集合:能够在多线程环境下安全使用的集合类。
  4. 原子变量:不可分割的操作,确保单一操作的原子性。

ReentrantLock

一个可重入的互斥锁,比内置锁(synchronized关键字)更灵活。

    public void methodOne() {
        try {
            // 使用ReentrantLock
            lock.lock();
            try {
                // 同步块
              System.out.println("hello");
            } finally {
                lock.unlock();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

上述同步同步代码块中的代码只能被单线程访问,单实例下不会出现线程安全问题。

CountDownLatch

一个计数器,等待其他线程完成一系列任务后才能继续。常用于主子线程任务协调,比如需要等子线程全部执行完成才执行主线程任务,比如常用的Excel文件导出。

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;

public class ExampleClass {
    
    private final CountDownLatch latch = new CountDownLatch(1);

    public void methodTwo() throws InterruptedException {
        // 使用CountDownLatch
        latch.await();
        // 继续执行任务
    }
}

CyclicBarrier

一组线程互相等待直到所有都到达某个点后再一起开始。

CyclicBarrier在Java的并发编程中非常有用,尤其是在需要固定数量的线程相互等待,以协调它们之间的执行顺序时。例如,在并行分解设计中,CyclicBarrier可以用于确保所有线程都完成其子任务后,再继续执行主任务。

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;

public class ExampleClass {
    
    private final CyclicBarrier barrier = new CyclicBarrier(2);

    public void methodThree() {
        // 使用CyclicBarrier
        try {
            barrier.await();
            // 所有线程到达屏障点后的动作
        } catch (InterruptedException | BrokenBarrierException e) {
            // 处理异常
        }
    }
}

Semaphore

允许多个线程进入受限区域的能力。

Java中的Semaphore是一个计数信号量,用于控制对多个资源的访问。它可以用于实现一些控制机制,比如限流、同步等。

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;

public class ExampleClass {
    
    private final Semaphore semaphore = new Semaphore(1);

    public void methodFour() {
        // 使用Semaphore
        if (semaphore.tryAcquire()) {
            try {
                // 可以执行的任务
            } finally {
                semaphore.release();
            }
        }
    }
}

ConcurrentHashMap


线程安全的HashMap。ConcurrentHashMap线程安全的原因得益于它的锁分级策略,ConcurrentHashMap将整个散列表分为许多个桶(bucket),每个桶都由一个锁保护。当多线程访问不同的桶时,可以并发进行。

并且在数据结构上采用了红黑树的数据结构,当链表长度超过某个阈值(8)时,链表会转换为红黑树,提高了查询的性能。

import java.util.concurrent.ConcurrentHashMap;
 
public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap map = new ConcurrentHashMap<>();
 
        // 插入元素
        map.put("one", 1);
        map.put("two", 2);
 
        // 获取元素
        Integer value = map.get("one");
        System.out.println("The value of 'one' is: " + value);
 
        // 删除元素
        map.remove("two");
 
        // 遍历ConcurrentHashMap
        for (String key : map.keySet()) {
            System.out.println("Key: " + key + ", Value: " + map.get(key));
        }
    }
}

CopyOnWriteArrayList

CopyOnWriteArrayList是Java并发包中的一个线程安全的ArrayList实现。它的设计原理是:当对其进行修改操作(add、set、remove等)时,会复制当前数组,并在新的数组上进行修改,然后再将原数组的引用指向新数组。

这种机制使得CopyOnWriteArrayList可以在无锁的情况下实现多线程的数据读取。

但是也是由于这个机制,使的CopyOnWriteArrayList只适用于读多写少的场景,如果是读少写多的场景,可能会产生内存溢出,这个大家使用的时候注意一下就好了。

其API基本和ArrayList一直,就不多做赘述了。

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ConcurrentLinkedQueue;

public class ExampleClass {
    
    private CopyOnWriteArrayList list = new CopyOnWriteArrayList<>();

    public void addToList(Integer element) {
        list.add(element);
    }
}

AtomicInteger & AtomicReference

AtomicInteger 是 Java 并发包中的一个原子整数类,它提供了一种用原子方式读取和更新整数值的方法。

AtomicInteger 的实现依赖于 Unsafe 类,该类提供了硬件级别的原子操作,它之所以能够保证操作的原子性,得益于Java底层的CAS乐观锁,关于CAS乐观锁,后续有时间我再整理一篇文章专门讲解。

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

public class ExampleClass {
    
    private AtomicInteger atomicInt = new AtomicInteger(0);
    private AtomicReference atomicRef = new AtomicReference<>(new Object());

    public int incrementInt() {
        return atomicInt.incrementAndGet();
    }

    public Object getRef() {
        return atomicRef.getAndSet(new Object());
    }
}

任务调度器

Java提供了ScheduledExecutorService来安排周期性任务。

ScheduledExecutorService是Java中用于执行定时任务的服务。它允许你提交RunnableCallable任务,并指定它们开始执行的时间。

以下是ScheduledExecutorService的一些核心方法:

  • schedule(Runnable, long, TimeUnit):安排在指定延迟后执行的一次性操作。
  • scheduleAtFixedRate(Runnable, long, long, TimeUnit):安排重复执行的定时任务,从初始延迟后开始,并且以指定的周期重复。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledTasks {

    public static void main(String[] args) {
        ScheduledExecutorService executor = Executors.ScheduledExecutorService(1);
        
        Runnable task = () -> System.out.println("Running a scheduled task");
        
        // 在延迟两秒后首次执行,之后每一秒执行一次
        executor.scheduleAtFixedRate(task, 2, 1, TimeUnit.SECONDS);
        
        // 在指定的时间后执行一次
        executor.schedule(() -> System.out.println("Once-off task"), 5, TimeUnit.SECONDS);
    }
}

总结

Java并发工具为多线程编程提供了强大的支持。它们减少了手动同步的需要,但仍然需要小心使用以避免死锁、竞态条件和其他并发问题。

务必熟悉每个工具的特定行为和限制,否则可能南辕北辙,所以代码中如果需要使用这些工具,需要搞清楚使用场景,谨慎小心的使用。

记住,尽管这些工具很方便,但它们并不是银弹;正确的设计和架构才是成功并发的关键。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表