java线程同步CoutDownLatch、CylicBarrier、Semsphore

简介: java线程同步CoutDownLatch、CylicBarrier、Semsphore

CountDownLatch

CountDownLatch是Java并发包(java.util.concurrent)中的一种同步工具,它允许一个或多个线程等待其他线程完成任务后再执行。CountDownLatch通常用于在多线程环境下协调任务的执行顺序。

CountDownLatch的基本用法如下:

  1. 创建一个CountDownLatch实例:
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3); // 初始化CountDownLatch,需要3个线程调用countDown()方法
        Thread thread1 = new Thread(new Task(latch, "Thread 1"));
        Thread thread2 = new Thread(new Task(latch, "Thread 2"));
        Thread thread3 = new Thread(new Task(latch, "Thread 3"));
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
class Task implements Runnable {
    private final CountDownLatch latch;
    private final String name;
    public Task(CountDownLatch latch, String name) {
        this.latch = latch;
        this.name = name;
    }
    @Override
    public void run() {
        try {
            System.out.println("Task " + name + " is running");
            Thread.sleep(1000); // 模拟任务执行时间
            System.out.println("Task " + name + " completed");
            latch.countDown(); // 当计数器减至0时,所有等待的线程将被唤醒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,我们创建了一个名为CountDownLatchExample的类。main()方法中,我们创建了一个CountDownLatch实例,并为3个线程分别分配了任务。然后,我们启动这3个线程。每个线程在完成任务后调用CountDownLatch的countDown()方法,当计数器减至0时,主线程将被唤醒。


CyclicBarrier

CyclicBarrier是Java并发包(java.util.concurrent)中的一种同步工具,它允许一组线程在达到某个共享状态时一起阻塞。CyclicBarrier主要用于协调多个线程之间的顺序执行或同步。

CyclicBarrier的基本用法如下:

  1. 创建一个CyclicBarrier实例:
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
    public static void main(String[] args) throws InterruptedException {
        CyclicBarrier barrier = new CyclicBarrier(3); // 初始化CyclicBarrier,需要3个线程调用await()方法
        Thread thread1 = new Thread(new Task(barrier, "Thread 1"));
        Thread thread2 = new Thread(new Task(barrier, "Thread 2"));
        Thread thread3 = new Thread(new Task(barrier, "Thread 3"));
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
class Task implements Runnable {
    private final CyclicBarrier barrier;
    private final String name;
    public Task(CyclicBarrier barrier, String name) {
        this.barrier = barrier;
        this.name = name;
    }
    @Override
    public void run() {
        try {
            System.out.println("Task " + name + " is running");
            Thread.sleep(1000); // 模拟任务执行时间
            System.out.println("Task " + name + " completed");
            barrier.await(); // 当所有线程都到达屏障时,主线程将被唤醒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,我们创建了一个名为CyclicBarrierExample的类。main()方法中,我们创建了一个CyclicBarrier实例,并为3个线程分别分配了任务。然后,我们启动这3个线程。每个线程在完成任务后调用CyclicBarrier的await()方法,当所有线程都到达屏障时,主线程将被唤醒。


Semaphore

Semaphore是Java并发包(java.util.concurrent)中的一种同步工具,它允许一组线程在达到某个共享状态时进行互斥访问。Semaphore有两个重要类型:

  1. Semaphore:Semaphore是一个计数信号量,用于控制同时访问的线程数量。创建一个Semaphore实例时,可以指定初始值和最大值。当一个线程尝试获取信号量时,如果计数小于最大值,则计数加1;否则,线程将等待直到计数减少到可用值。
  2. CountDownLatch:CountDownLatch也是一个计数信号量,但它允许一个或多个线程在到达某个共享状态后继续执行。创建一个CountDownLatch实例时,可以指定初始值。当一个或多个线程调用countDown()方法时,计数减1。当计数变为0时,所有等待的线程都将被唤醒。

下面是Semaphore的示例代码:

import java.util.concurrent.Semaphore;
public class SemaphoreExample {
    public static void main(String[] args) throws InterruptedException {
        int initialValue = 5; // 初始化Semaphore,允许5个线程同时访问
        int maxValue = 10; // 最大允许访问的线程数为10
        Semaphore semaphore = new Semaphore(initialValue, maxValue); // 创建一个Semaphore实例,初始值为5,最大值为10
        Thread thread1 = new Thread(new Task(semaphore));
        Thread thread2 = new Thread(new Task(semaphore));
        Thread thread3 = new Thread(new Task(semaphore));
        Thread thread4 = new Thread(new Task(semaphore));
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}
class Task implements Runnable {
    private final Semaphore semaphore;
    public Task(Semaphore semaphore) {
        this.semaphore = semaphore;
    }
    @Override
    public void run() {
        try {
            semaphore.acquire(); // 尝试获取信号量,如果可用则计数加1,否则等待直到可用
            System.out.println("Thread " + Thread.currentThread().getName() + " is running");
            Thread.sleep(1000); // 模拟任务执行时间
            semaphore.release(); // 释放信号量,计数减1
            System.out.println("Thread " + Thread.currentThread().getName() + " completed");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

CoutDownLatch和CylicBarrier区别

CountDownLatch和CyclicBarrier都是Java并发包(java.util.concurrent)中用于协调多个线程之间同步的工具,但它们在实现上有所不同。

1.CountDownLatch

CountDownLatch是一个计数信号量,允许一个或多个线程在到达某个共享状态后继续执行。当一个或多个线程调用countDown()方法时,计数减1。当计数变为0时,所有等待的线程都将被唤醒。CountDownLatch通常与Semaphore一起使用,以控制同时访问的资源数量。

示例代码:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        int initialValue = 5; // 初始化CountDownLatch,允许5个线程同时执行countDown()方法
        int maxValue = 10; // 最大允许执行的线程数为10
        CountDownLatch countDownLatch = new CountDownLatch(initialValue); // 创建一个CountDownLatch实例,初始值为5
        for (int i = 0; i < initialValue; i++) {
            new Thread(new Task(countDownLatch)).start(); // 创建多个线程,每个线程都调用countDown()方法
        }
        countDownLatch.await(); // 所有线程执行完countDown()方法后,主线程才会继续执行
        System.out.println("All threads completed");
    }
}
class Task implements Runnable {
    private final CountDownLatch countDownLatch;
    public Task(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }
    @Override
    public void run() {
        try {
            countDownLatch.countDown(); // 每调用一次countDown()方法,计数减1
            System.out.println("Thread " + Thread.currentThread().getName() + " is running");
            Thread.sleep(1000); // 模拟任务执行时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            countDownLatch.countDown(); // 在finally块中再次调用countDown()方法,确保所有线程都执行完countDown()方法后计数减1
        }
    }
}

CoutDownLatch是所有子线程都准备好后再同时开始,而CyclicBarrier是所有线程结束后再一起回到主线程。

相关文章
|
1月前
|
安全 Java
深入Java并发编程:线程同步与互斥机制
【4月更文挑战第6天】Java并发编程中,确保数据一致性与防止条件竞争是关键。语言提供`synchronized`关键字、`Lock`接口和原子变量等机制处理并发问题。线程同步问题包括竞态条件、死锁和活锁。`synchronized`实现内置锁,`Lock`接口提供更灵活的锁管理,原子变量则支持无锁安全操作。理解并恰当使用这些工具能有效管理并发,避免数据不一致。
|
2月前
|
Java 云计算
Java多线程编程中的同步与互斥机制探析
在当今软件开发领域,多线程编程是一项至关重要的技能。本文将深入探讨Java中的同步与互斥机制,分析其在多线程环境下的应用及实现原理,帮助读者更好地理解并运用这一关键技术。
24 4
|
13天前
|
Java 程序员 开发者
深入理解Java并发编程:线程同步与锁机制
【4月更文挑战第30天】 在多线程的世界中,确保数据的一致性和线程间的有效通信是至关重要的。本文将深入探讨Java并发编程中的核心概念——线程同步与锁机制。我们将从基本的synchronized关键字开始,逐步过渡到更复杂的ReentrantLock类,并探讨它们如何帮助我们在多线程环境中保持数据完整性和避免常见的并发问题。文章还将通过示例代码,展示这些同步工具在实际开发中的应用,帮助读者构建对Java并发编程深层次的理解。
|
1天前
|
安全 算法 Java
Java一分钟:线程同步:synchronized关键字
【5月更文挑战第11天】Java中的`synchronized`关键字用于线程同步,防止竞态条件,确保数据一致性。本文介绍了其工作原理、常见问题及避免策略。同步方法和同步代码块是两种使用形式,需注意避免死锁、过度使用导致的性能影响以及理解锁的可重入性和升级降级机制。示例展示了同步方法和代码块的运用,以及如何避免死锁。正确使用`synchronized`是编写多线程安全代码的核心。
49 2
|
4天前
|
安全 C++
C++多线程编程:并发与同步
C++多线程编程:并发与同步
8 0
|
19天前
|
监控 安全 Java
一文讲明白Java中线程与进程、并发与并行、同步与异步
一文讲明白Java中线程与进程、并发与并行、同步与异步
8 1
|
26天前
|
安全 算法 Java
Java中的多线程并发控制与同步机制
【4月更文挑战第17天】 在现代软件开发中,Java作为一种广泛使用的编程语言,其对多线程的支持是构建高性能应用程序的关键。本文将深入探讨Java中的多线程并发控制与同步机制,包括基本的线程创建、生命周期管理,以及高级的并发工具如synchronized关键字、ReentrantLock类、并发集合和原子变量等。通过理论分析与实例演示,旨在为读者提供一个清晰的多线程并发控制与同步的实现框架,并指出在实践中如何避免常见的并发问题,如死锁、竞态条件和资源争用等。
|
26天前
|
安全 Java 开发者
Java中的多线程并发控制与同步机制
【4月更文挑战第17天】在Java编程中,多线程是实现并行处理和提高程序性能的重要手段。然而,随之而来的线程安全问题和数据一致性问题不容忽视。本文深入剖析了Java中多线程的并发控制与同步机制,包括synchronized关键字、显式锁Lock以及并发集合等高级特性。通过对比分析这些机制的原理和使用场景,旨在帮助开发者理解并合理运用于实际项目中,以解决并发环境下的数据竞争和资源冲突问题。
|
26天前
|
存储 缓存 安全
Java并发基础之互斥同步、非阻塞同步、指令重排与volatile
在Java中,多线程编程常常涉及到共享数据的访问,这时候就需要考虑线程安全问题。Java提供了多种机制来实现线程安全,其中包括互斥同步(Mutex Synchronization)、非阻塞同步(Non-blocking Synchronization)、以及volatile关键字等。 互斥同步(Mutex Synchronization) 互斥同步是一种基本的同步手段,它要求在任何时刻,只有一个线程可以执行某个方法或某个代码块,其他线程必须等待。Java中的synchronized关键字就是实现互斥同步的常用手段。当一个线程进入一个synchronized方法或代码块时,它需要先获得锁,如果
26 0
|
28天前
|
存储 缓存 Java
线程同步的艺术:探索 JAVA 主流锁的奥秘
本文介绍了 Java 中的锁机制,包括悲观锁与乐观锁的并发策略。悲观锁假设多线程环境下数据冲突频繁,访问前先加锁,如 `synchronized` 和 `ReentrantLock`。乐观锁则在访问资源前不加锁,通过版本号或 CAS 机制保证数据一致性,适用于冲突少的场景。锁的获取失败时,线程可以选择阻塞(如自旋锁、适应性自旋锁)或不阻塞(如无锁、偏向锁、轻量级锁、重量级锁)。此外,还讨论了公平锁与非公平锁,以及可重入锁与非可重入锁的特性。最后,提到了共享锁(读锁)和排他锁(写锁)的概念,适用于不同类型的并发访问需求。
256 2