龙空技术网

JDK并发包中的线程同步工具类(2)

架构师笔记 58

前言:

此时朋友们对“java中thread类在哪个包”可能比较关注,看官们都需要分析一些“java中thread类在哪个包”的相关资讯。那么小编在网上汇集了一些关于“java中thread类在哪个包””的相关内容,希望姐妹们能喜欢,我们一起来了解一下吧!

背景

Java并发库提供了大量的线程同步类,用于实现线程同步。以下是一些常用的Java并发库中的线程同步类:

CountDownLatch:可以实现多个线程间的协作。

CyclicBarrier:它允许一组线程在到达某个公共屏障点之前阻塞,直到最后一个线程到达,然后所有线程再继续执行。

Exchanger:Java并发包中的一个工具类,用于实现两个线程之间的数据交换

Semaphore:它控制一个资源(如数据库连接)的访问,保证在任意时刻只有一定数量的线程可以访问该资源。

Phaser:适用于分阶段地执行多个任务,并在每个阶段等待所有任务完成后再继续执行;

Lock:它是一种互斥锁,它可以实现对共享资源的独占访问。

ReentrantLock:它是一种可重入的互斥锁,它支持多次获取锁,并且必须多次释放锁以释放锁的所有权。

使用示例

Exchanger的主要特点如下:

数据交换:Exchanger允许两个线程在同一个时间点上交换数据。每个线程通过调用exchange()方法来交换数据。当一个线程调用exchange()方法时,它会被阻塞,直到另一个线程也调用了exchange()方法。线程间同步:Exchanger提供了一个同步点,当两个线程都到达这个点时,它们可以交换数据。这可以用于实现线程间的同步,确保两个线程在某个时间点上都具备了需要的数据。数据一致性:Exchanger可以保证数据的一致性。当两个线程交换数据时,它们可以确保在交换点之前的操作已经完成,而在交换点之后的操作还没有开始。

使用Exchanger时,需要注意以下几点:

Exchanger只能用于两个线程之间的数据交换。如果有多个线程需要交换数据,可以使用多个Exchanger对象。Exchanger的exchange()方法可以传递数据。当一个线程调用exchange()方法时,它可以将数据传递给另一个线程,并接收另一个线程传递的数据。Exchanger的exchange()方法可能会抛出InterruptedException异常。当一个线程在调用exchange()方法时被中断,它会抛出InterruptedException异常。

下面是一个使用Exchanger的简单示例:

import java.util.concurrent.Exchanger;public class ExchangerExample {    public static void main(String[] args) {        Exchanger<String> exchanger = new Exchanger<>();        Thread thread1 = new Thread(() -> {            try {                String data = "Hello from Thread 1";                String receivedData = exchanger.exchange(data);                System.out.println("Thread 1 received: " + receivedData);            } catch (InterruptedException e) {                e.printStackTrace();            }        });        Thread thread2 = new Thread(() -> {            try {                String data = "Hello from Thread 2";                String receivedData = exchanger.exchange(data);                System.out.println("Thread 2 received: " + receivedData);            } catch (InterruptedException e) {                e.printStackTrace();            }        });        thread1.start();        thread2.start();    }}

在上述示例中,我们创建了一个Exchanger对象,并创建了两个线程。每个线程通过调用exchange()方法来交换数据。当一个线程调用exchange()方法时,它会被阻塞,直到另一个线程也调用了exchange()方法。当两个线程都到达交换点时,它们可以交换数据,并继续执行后续操作。运行上述示例,可以看到两个线程交换数据并打印接收到的数据。

Semaphore(信号量)是Java并发包中的一个工具类,用于控制并发访问资源的数量。它可以用来限制同时访问某个资源的线程数量,或者用于实现线程间的同步。

Semaphore的主要特点如下:

计数器:Semaphore内部维护了一个计数器,用于记录当前可用的许可证数量。许可证的数量可以通过构造函数来指定。获取许可证:线程可以通过调用Semaphore的acquire()方法来获取许可证。如果当前许可证的数量大于0,那么线程可以立即获取许可证,并将许可证数量减1。如果当前许可证的数量为0,那么线程将被阻塞,直到有其他线程释放许可证。释放许可证:线程可以通过调用Semaphore的release()方法来释放许可证。这会将许可证数量加1,并唤醒一个等待的线程。

使用Semaphore时,需要注意以下几点:

Semaphore可以用于限制同时访问某个资源的线程数量。通过控制许可证的数量,可以限制同时访问某个资源的线程数量。Semaphore可以用于实现线程间的同步。通过控制许可证的数量,可以确保某个操作只有在其他线程完成之后才能执行。Semaphore的acquire()方法和release()方法可以被中断。当一个线程在调用acquire()方法或release()方法时被中断,它会抛出InterruptedException异常。

下面是一个使用Semaphore的简单示例:

import java.util.concurrent.Semaphore;public class SemaphoreExample {    public static void main(String[] args) {        Semaphore semaphore = new Semaphore(1);        Thread thread1 = new Thread(() -> {            try {                semaphore.acquire();                System.out.println("Thread 1 acquired the semaphore");                Thread.sleep(2000);                System.out.println("Thread 1 released the semaphore");                semaphore.release();            } catch (InterruptedException e) {                e.printStackTrace();            }        });        Thread thread2 = new Thread(() -> {            try {                semaphore.acquire();                System.out.println("Thread 2 acquired the semaphore");                Thread.sleep(2000);                System.out.println("Thread 2 released the semaphore");                semaphore.release();            } catch (InterruptedException e) {                e.printStackTrace();            }        });        thread1.start();        thread2.start();    }}

在上述示例中,我们创建了一个Semaphore对象,并设置初始许可证数量为1。然后创建了两个线程,每个线程在获取许可证之前会被阻塞,直到许可证可用。当一个线程获取到许可证后,它会执行一些操作,并在操作完成后释放许可证。另一个线程在前一个线程释放许可证之后才能获取许可证。运行上述示例,可以看到两个线程交替地获取和释放许可证。

注意:Semaphore类的构造方法可以接受一个fairness参数,当这个参数设置为false时,此类不保证线程获取到许可令牌的顺序,特别是当运行抢夺资源时,意味着一个线程使用acquire获取许可令牌的时间可能会比一个等待队列在它之前的线程获取到令牌更早--逻辑上来说,新线程放置月等待队列的头部。当fairness参数设置为true时,Semaphore保证线程调用acquire方法时的顺序获取到令牌(即先进先出FIFO)。

Phaser(分段器)是Java并发包中的一个工具类,用于控制多个线程的同步。它可以用于分阶段地执行多个任务,并在每个阶段等待所有任务完成后再继续执行。

Phaser的主要特点如下:

阶段:Phaser将任务的执行分为多个阶段。每个阶段可以包含多个任务,任务可以是线程或其他实现了Phaser的对象。在每个阶段结束时,Phaser会等待所有任务完成后再继续执行下一个阶段。注册任务:任务可以通过调用Phaser的register()方法来注册。注册后,任务会被加入到Phaser的任务列表中,并参与到后续的阶段执行中。到达阶段:任务可以通过调用Phaser的arrive()方法来通知Phaser自己已经到达当前阶段。当所有任务都到达当前阶段时,Phaser会继续执行下一个阶段。等待阶段:任务可以通过调用Phaser的awaitAdvance()方法来等待当前阶段的任务完成。当所有任务都完成后,awaitAdvance()方法会返回下一个阶段的序号。

使用Phaser时,需要注意以下几点:

Phaser可以用于分阶段地执行多个任务。通过将任务划分为多个阶段,并在每个阶段等待所有任务完成后再继续执行,可以实现复杂的并发控制逻辑。Phaser可以用于实现线程间的同步。通过等待所有任务完成后再继续执行,可以确保某个操作只有在其他线程完成之后才能执行。Phaser的register()方法和arrive()方法可以被中断。当一个线程在调用register()方法或arrive()方法时被中断,它会抛出InterruptedException异常。

下面是一个使用Phaser的简单示例:

import java.util.concurrent.Phaser;public class PhaserExample {    public static void main(String[] args) {        Phaser phaser = new Phaser(3);        Thread thread1 = new Thread(() -> {            System.out.println("Thread 1 started");            phaser.arriveAndAwaitAdvance();            System.out.println("Thread 1 finished");        });        Thread thread2 = new Thread(() -> {            System.out.println("Thread 2 started");            phaser.arriveAndAwaitAdvance();            System.out.println("Thread 2 finished");        });        Thread thread3 = new Thread(() -> {            System.out.println("Thread 3 started");            phaser.arriveAndAwaitAdvance();            System.out.println("Thread 3 finished");        });        thread1.start();        thread2.start();        thread3.start();    }}

在上述示例中,我们创建了一个Phaser对象,并设置初始参与者数量为3。然后创建了三个线程,每个线程在执行任务之前会调用arriveAndAwaitAdvance()方法来通知Phaser自己已经到达当前阶段,并等待其他任务完成。当所有任务都到达当前阶段后,Phaser会继续执行下一个阶段。运行上述示例,可以看到三个线程交替地执行,并在每个阶段等待其他线程完成后再继续执行。

总结

Phaser和CyclicBarrier是Java并发包中用于控制多个线程同步的工具类,它们在功能和使用方式上有一些区别。

功能:Phaser可以用于分阶段地执行多个任务,并在每个阶段等待所有任务完成后再继续执行。它可以动态地增加或减少参与者的数量,并且可以被重用。而CyclicBarrier用于等待一组线程到达某个公共屏障点,然后同时继续执行。它的参与者数量是固定的,并且一旦所有参与者都到达屏障点,CyclicBarrier就会被重置,可以被多次使用。参与者数量:Phaser的参与者数量是可变的,可以通过register()方法动态地增加或减少参与者的数量。而CyclicBarrier的参与者数量是固定的,需要在创建CyclicBarrier对象时指定。等待方式:Phaser使用arriveAndAwaitAdvance()方法来等待其他任务完成,并在所有任务完成后继续执行。CyclicBarrier使用await()方法来等待其他线程到达屏障点,并在所有线程都到达后同时继续执行。高级功能:Phaser提供了一些额外的高级功能,如分阶段执行、任务分组、动态注册等。它还可以用于实现复杂的并发控制逻辑。CyclicBarrier没有这些高级功能,只提供了简单的线程同步功能。

综上所述,Phaser适用于分阶段地执行多个任务,并在每个阶段等待所有任务完成后再继续执行;而CyclicBarrier适用于等待一组线程到达某个公共屏障点,并在所有线程到达后同时继续执行。

标签: #java中thread类在哪个包