多线程学习,CountDownLatch,CyclicBarrier,Semaphore使用实例

在一般小型开发项目中,其实用不到多线程,但是这个概念以及内容是非常重要的,牵扯到的知识点也非常多。

首先多线程的四种方式

1、集成Thread类

2、实现Runable接口

3、实Callable接口

4、线程池

但其实开启多线程我们一般推荐用实现接口的方法而不是继承,因为在java中只能单继承多实现,如果通过继承开启多线程,少了很多扩展性,实现接口比较灵活,要给自己留后路。

而对于Runable和Callable来说,区别其实就是Callable可以自定义抛出异常。

线程中核心的两个方法是run(),start()方法,如果直接调用对象的run()方法只会运行一次,需要使用start()才能真正开启多线程。

顺带提一嘴线程的生命周期:新建,就绪,阻塞,运行,销毁

线程阻塞的方式:sleep(),wait(),join(),yield()

其中sleep和wait区别就是wait会释放对象锁,结束阻塞后会重新获取对象锁,跟wait()相关联的两个方法notify和notifyall,notify可能会导致死锁,并且sleep和join以及yield都是Thread方法,wait(),notify(),notifyall()都是Object方法

所有的理论都是为了最后的实践,接下来会讲解线程当中必不可少的CountDownLatch,CyclicBarrier,Semaphore使用方法和实例。

为什么会有这些方法的使用,最重要的就是有他所需要的场景

1、CountDownLatch,类似于用一个栅栏去挡住子线程,子线程每次会使计数减一,当计数完毕之1后,主线程调用await()方法继续后续的逻辑处理,类似场景如在很多计算量大的场景,使用多线程并发提高效率之后,需要保证主线程后续计算是子线程计算之后正确的值,就可以使用CountDownLatch进行主线程等待子线程执行完之后再进行执行。

实例

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个 CountDownLatch,计数为 5,表示需要等待 5 个任务完成  
        CountDownLatch latch = new CountDownLatch(5);

        // 创建一个线程池  
        ExecutorService executor = Executors.newFixedThreadPool(5);

        // 提交 5 个任务到线程池  
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("线程 " + Thread.currentThread().getId() + " 正在执行任务 " + taskId);
//                 模拟任务耗时
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                // 任务完成后,计数器减一  
                latch.countDown();
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("所有任务已经完成,子线程继续执行");
            });
        }

        // 主线程等待 CountDownLatch 计数归零  
        latch.await();
        System.out.println("所有任务已经完成,主线程继续执行");

        // 关闭线程池  
        executor.shutdown();
    }
}

2、CyclicBarrier,原理和CountDownLatch类似,只不过在此处是由子线程调用await()方法进行计数减一和阻塞,当所有子线程都执行到阻塞节点之后,再统一允许后续代码。

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

public class CyclicBarrierExample {
    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
        // 创建一个CyclicBarrier,指定参与同步的线程数量
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);

        // 创建并启动三个线程
        new Thread(() -> {
            try {
                System.out.println("线程1准备完毕,等待其他线程...");
                cyclicBarrier.await(); // 线程在此等待
                System.out.println("线程1开始执行后续任务...");
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                System.out.println("线程2准备完毕,等待其他线程...");
                cyclicBarrier.await(); // 线程在此等待
                System.out.println("线程2开始执行后续任务...");
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                System.out.println("线程3准备完毕,等待其他线程...");
                cyclicBarrier.await(); // 线程在此等待
                System.out.println("线程3开始执行后续任务...");
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

3、Semaphore,类似于给予许可权限,线程才能执行后续代码,比如说设置五个许可,给线程池提交了十个任务,那么同时并发执行后续的任务最多只有五个,会通过semaphore.acquire()获取许可,有剩余许可继续执行,没有则进行等待,这里要注意,无论是否正确执行,都要释放许可semaphore.release()

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    // 假设有一个资源池,比如数据库连接池,最大只能支持5个并发访问  
    private final Semaphore semaphore = new Semaphore(5);

    public void doSomethingWithResource() {
        try {
            // 获取许可,如果没有许可则等待  
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + " 获得了许可,正在访问资源...");

            // 模拟资源访问的耗时操作  
            Thread.sleep(1000);

            System.out.println(Thread.currentThread().getName() + " 释放了许可,完成资源访问...");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 无论是否发生异常,都要释放许可  
            semaphore.release();
        }
    }

    public static void main(String[] args) {
        SemaphoreExample example = new SemaphoreExample();
        ExecutorService executor = Executors.newFixedThreadPool(10); // 创建一个固定大小的线程池  

        // 提交10个任务到线程池  
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.submit(() -> {
                example.doSomethingWithResource();
            });
        }

        // 关闭线程池(这里只是示例,实际使用时可能需要更复杂的逻辑来优雅关闭线程池)  
        executor.shutdown();
    }
}

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值