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

yizhihongxing

一文详解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日

相关文章

  • JSP struts2 url传参中文乱码解决办法

    JSP struts2 url传参中文乱码解决办法 问题描述 在使用 JSP 和 Struts2 构建 Web 应用程序时,我们常常需要通过 URL 传参。但是,如果参数中包含中文等非 ASCII 字符,就会出现乱码的问题。这是因为浏览器默认使用的是 ISO-8859-1 编码方式,而中文需要使用 UTF-8 编码,两种编码方式不同,导致乱码的出现。 解决办…

    Java 2023年6月15日
    00
  • 详解SpringBoot 创建定时任务(配合数据库动态执行)

    先来介绍一下 SpringBoot 这个框架。SpringBoot 是一款基于 Spring 框架的快速开发框架,能够帮助开发者快速搭建 Spring 应用,极大地提高了开发效率。在 SpringBoot 中,我们可以非常简单地创建定时任务并进行动态执行,下面是详解 SpringBoot 创建定时任务(配合数据库动态执行)的攻略: 一、引入相关依赖 在创建我…

    Java 2023年5月20日
    00
  • 解决window.location.href之后session丢失的问题

    如果在页面中使用了 window.location.href 来进行页面的跳转,那么有可能会导致 session 丢失的问题,因为这种方式会导致浏览器重新发起一个新的请求,从而导致服务端的 session 丢失。下面是解决这个问题的完整攻略: 一、问题分析 首先分析为什么会导致 session 丢失,原因如下: 当使用 window.location.hre…

    Java 2023年6月16日
    00
  • Springboot异常日志输出方式

    当Spring Boot应用程序出现异常时,我们需要能够及时发现并定位问题,根据异常信息进行问题解决。下面是Spring Boot异常日志输出方式的完整攻略: 1. 添加日志依赖 在Spring Boot 2.x版本中,Spring Boot默认集成了slf4j作为日志框架。可以通过在pom.xml文件中添加spring-boot-starter-loggi…

    Java 2023年5月26日
    00
  • Mybatis传递多个参数的三种实现方法

    Mybatis是Java开发中常用的ORM(对象关系映射)框架之一。在使用Mybatis进行开发时,有时需要传递多个参数给SQL语句进行处理。本文将详细介绍Mybatis传递多个参数的三种实现方法。 实现方法一:使用Map封装参数 可以使用Map集合来封装多个参数,在SQL语句中通过名称来获取相应的参数。示例代码如下: public interface Us…

    Java 2023年5月20日
    00
  • Java8深入学习之熟透Optional

    Java8深入学习之熟透Optional Java8引入了Optional类型,用于解决空指针异常问题。本文将深入讲解Optional的使用,并提供完整攻略,以帮助读者更好地使用和理解Optional。 什么是Optional? Optional是Java8引入的一个容器(Container)对象,用于处理空指针异常。它可以包含一个非null的对象,也可以为…

    Java 2023年5月26日
    00
  • 理解Java面向对象编程设计

    理解Java面向对象编程设计的完整攻略 1. 理解什么是面向对象编程设计 面向对象编程设计(Object-Oriented Programming,OOP)是一种软件开发范式,基于对象的概念进行编程。其重点在于数据和行为的封装,通过封装来降低耦合度。面向对象的语言中,一切皆为对象。通过对象的封装、继承、多态等特性,编写出高效、灵活、可维护的程序。 2. Ja…

    Java 2023年5月30日
    00
  • Java后端长时间无操作自动退出的实现方式

    实现Java后端长时间无操作自动退出,主要需要使用Java的定时器和线程等相关技术。 以下是实现Java后端长时间无操作自动退出的完整攻略: 第一步:设置最大空闲时间和定时器 首先,我们需要设置一个最大空闲时间,当用户最后一次请求后,超过了该时间,就会被认为是无操作状态。例如,我们设置最大空闲时间为10分钟。 接下来,我们需要使用Java的定时器,定时器会在…

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