一文详解Java闭锁和栅栏的实现

一文详解Java闭锁和栅栏的实现

1. 什么是闭锁和栅栏

在并发编程中,有时需要等待某个操作的完成,或者协调多个线程的执行。Java提供了闭锁(Latch)和栅栏(Barrier)两个机制来实现这种协调。

闭锁是一种同步工具,可以使线程等待一个或多个线程的操作完成。闭锁一般会在某个线程等待另一个线程完成任务时使用。

栅栏是一种同步工具,它允许一组线程在某个点上进行相互等待,直到所有线程都到达此点,然后再一起继续执行。栅栏通常用于协调多个线程相互等待,等到所有线程都准备好后再统一执行。

2. 闭锁的实现

Java中闭锁的实现主要有两种方式:CountDownLatch和FutureTask。

2.1 CountDownLatch

CountDownLatch是一个计数器,初始值可以指定,当一个线程完成自己的任务后,会调用countDown()方法,计数器的值会减一。其他线程在等待该操作完成时,通过await()方法来等待,当计数器为0时,所有的线程就会被唤醒,然后继续执行。

下面是一个简单的CountDownLatch示例:

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);

        new Worker("Worker1", latch).start();
        new Worker("Worker2", latch).start();
        new Worker("Worker3", latch).start();

        latch.await();

        System.out.println("All workers have finished.");
    }

    static class Worker extends Thread {
        private CountDownLatch latch;

        public Worker(String name, CountDownLatch latch) {
            super(name);
            this.latch = latch;
        }

        @Override
        public void run() {
            System.out.println(getName() + " is working");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName() + " has finished");
            latch.countDown();
        }
    }
}

运行结果:

Worker1 is working
Worker2 is working
Worker3 is working
Worker1 has finished
Worker2 has finished
Worker3 has finished
All workers have finished.

2.2 FutureTask

FutureTask也可以用来实现闭锁的功能。它可以安排一个Callable任务在FutureTask构造时执行,然后返回一个Future对象。可以在程序的任何时候调用Future的get()方法获取结果,获取结果时如果任务还没有执行完成,当前线程就会被阻塞。

下面是一个简单的FutureTask示例:

import java.util.concurrent.*;

public class FutureTaskExample {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("Task is running");
                Thread.sleep(1000);
                System.out.println("Task has finished");
                return "Done";
            }
        });

        executor.execute(futureTask);

        System.out.println("Waiting for result");
        String result = futureTask.get();
        System.out.println("Got result: " + result);
        executor.shutdown();
    }
}

运行结果:

Task is running
Waiting for result
Task has finished
Got result: Done

3. 栅栏的实现

Java中栅栏的实现有两种方式:CyclicBarrier和Exchanger。

3.1 CyclicBarrier

CyclicBarrier也是一个计数器,但它与CountDownLatch不同的是,CyclicBarrier要等所有线程都完成工作后才会继续执行。CyclicBarrier的计数器可以重复使用,也就是说,当所有线程都到达栅栏后,计数器又会重新恢复初始值。

下面是一个简单的CyclicBarrier示例:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public static void main(String[] args) {
        final int count = 3;
        CyclicBarrier barrier = new CyclicBarrier(count, new Runnable() {
            @Override
            public void run() {
                System.out.println("All threads have reached the barrier.");
            }
        });

        new Worker("Worker1", barrier).start();
        new Worker("Worker2", barrier).start();
        new Worker("Worker3", barrier).start();
    }

    static class Worker extends Thread {
        private CyclicBarrier barrier;

        public Worker(String name, CyclicBarrier barrier) {
            super(name);
            this.barrier = barrier;
        }

        @Override
        public void run() {
            System.out.println(getName() + " is working");
            try {
                Thread.sleep((int) (Math.random() * 3000));
                System.out.println(getName() + " has reached the barrier");
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

Worker1 is working
Worker2 is working
Worker3 is working
Worker1 has reached the barrier
Worker3 has reached the barrier
Worker2 has reached the barrier
All threads have reached the barrier.

3.2 Exchanger

Exchanger也可以用来实现栅栏的功能。Exchanger的主要作用是使两个线程可以互相交换数据。当线程A调用Exchanger的exchange()方法时,它会阻塞等待另一个线程B调用exchange()方法,然后交换数据。

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

import java.util.concurrent.Exchanger;

public class ExchangerExample {
    public static void main(String[] args) throws InterruptedException {
        final Exchanger<String> exchanger = new Exchanger<>();

        new Worker("Worker1", exchanger).start();
        new Worker("Worker2", exchanger).start();
    }

    static class Worker extends Thread {
        private Exchanger<String> exchanger;

        public Worker(String name, Exchanger<String> exchanger) {
            super(name);
            this.exchanger = exchanger;
        }

        @Override
        public void run() {
            System.out.println(getName() + " is working");
            try {
                Thread.sleep((int) (Math.random() * 3000));
                System.out.println(getName() + " is exchanging data with " + Thread.currentThread().getName());
                String data = exchanger.exchange("Hello from " + getName());
                System.out.println(getName() + " has received data: " + data);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

Worker1 is working
Worker2 is working
Worker1 is exchanging data with Worker2
Worker2 is exchanging data with Worker1
Worker1 has received data: Hello from Worker2
Worker2 has received data: Hello from Worker1

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一文详解Java闭锁和栅栏的实现 - Python技术站

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

相关文章

  • 详解Java中ArrayList类

    我们来详细讲解Java中ArrayList类的完整攻略。 1. ArrayList类简介 Java中的ArrayList类是一种可以动态增长和缩小大小的数组,是一种可重用的数据集合,ArrayList中的元素可以是任意类型的对象。 相对于传统的Java数组,ArrayList类可以自动扩容,同时可以动态增删元素,因此使用起来更加方便。 2. ArrayLis…

    Java 2023年5月26日
    00
  • Flink自定义Sink端实现过程讲解

    好的。首先,讲解Flink自定义Sink端实现过程,我们需要先了解Flink中DataStream API中对于Sink的定义。 Flink中,DataStream API提供了一些内置的Sink操作,如print、writeAsText等。这些内置的Sink操作可以满足大部分常见的业务需求,但对于一些特殊的需求,我们可能需要自己实现一些自定义的Sink操作…

    Java 2023年5月20日
    00
  • 这可能是最全面的MySQL面试八股文了

    什么是MySQL MySQL是一个关系型数据库,它采用表的形式来存储数据。你可以理解成是Excel表格,既然是表的形式存储数据,就有表结构(行和列)。行代表每一行数据,列代表该行中的每个值。列上的值是有数据类型的,比如:整数、字符串、日期等等。 数据库的三大范式 第一范式1NF 确保数据库表字段的原子性。最全面的Java面试网站 比如字段 userInfo:…

    Java 2023年4月25日
    00
  • jsp网页登陆验证

    下面是 JSP 网页登陆验证的完整攻略: 1. 概述 在 JSP 开发中,经常需要进行用户登录验证。其中,登陆验证的基本过程为:用户将自己的用户名和密码输入到登录页面上,点击登录按钮后,通过将用户输入的账号和密码与数据库中存储的用户信息进行比对,来验证用户身份是否合法。在本文中,我们将从前端页面设计、后端数据库连接、用户验证等多个方面进行讲解,帮助大家更好地…

    Java 2023年6月15日
    00
  • JavaWeb实现图形报表折线图的方法

    下面就是JavaWeb实现图形报表折线图的方法的完整攻略: 1. 准备工作 在实现JavaWeb图形报表折线图前,我们需要先准备好以下资源: 前端使用的图表库,例如ECharts、Highcharts等; 后端使用的JavaWeb框架,例如Spring、Struts2等; 数据库,用于存储数据; 数据库连接池,用于连接数据库。 2. 使用ECharts绘制折…

    Java 2023年6月15日
    00
  • 浅谈十个常见的Java异常出现原因

    浅谈十个常见的Java异常出现原因 在Java编程过程中,我们难免会遇到各种各样的异常情况,因此了解常见的Java异常出现原因,可以帮助我们更快地定位和解决问题。下面是10种常见的Java异常及其出现原因: 1. NullPointerException NullPointerException是Java程序员经常会遇到的异常之一,它表示试图访问一个空对象的…

    Java 2023年5月26日
    00
  • Java线程池由浅入深掌握到精通

    Java线程池从入门到精通 Java线程池是一种多线程处理机制,用于管理和调度多个线程。通过线程池,可以复用线程、控制线程数量,从而提高程序并发处理能力和资源利用率。 1. 初识Java线程池 1.1 线程池的优点 使用线程池具有以下优点: 降低线程创建和销毁带来的性能损耗; 通过重用线程来优化程序性能; 可以对线程数量进行限制和控制,避免系统资源被消耗殆尽…

    Java 2023年5月19日
    00
  • java实现轻量型http代理服务器示例

    Java实现轻量型HTTP代理服务器示例 在本攻略中,我们将使用Java编程语言演示如何实现一个轻量型的HTTP代理服务器。HTTP代理服务器是一种可以用于加速Web应用程序的常用中间件,其可以缓存常见的HTTP请求以减少Web服务器的负载。它也可以提供安全性功能,例如过滤内容和验证客户端请求。接下来就跟随本攻略一步步了解Java实现轻量型HTTP代理服务器…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部