博客
关于我
java并发编程之线程协作
阅读量:380 次
发布时间:2019-03-05

本文共 6576 字,大约阅读时间需要 21 分钟。

Java多线程编程中的多种锁机制解析

在Java多线程编程中,多线程是提升程序效率的重要手段。多个线程能够同时执行不同的任务,从而大大提高程序的运行速度。然而,多线程编程也需要有序地管理线程之间的协作与资源共享。以下将从Semaphore、CountDownLatch、CyclicBarrier、Lock以及Condition等多线程控制工具进行详细讲解。

一、Semaphore(信号灯)

Semaphore是一种轻量级的同步机制,常用于资源的互相独占或共享。它类似于操作系统中的信号灯,用于限制某种资源的使用数量。Semaphore的典型应用场景包括线程池、数据库连接池等。

使用场景:
  • 线程池调度:Semaphore可以限制线程池中同时运行的线程数量。例如,ExecutorService结合Semaphore可以实现线程池的资源控制。
  • 资源共享:Semaphore还可以用来共享资源。例如,数据库连接池可以使用Semaphore来控制连接的使用数量。
示例代码:
public class SemaphoreDemo {    private static Semaphore semaphore = new Semaphore(3); // 初始化信号灯,允许最多3个线程同时通过    public static void main(String[] args) {        ExecutorService service = Executors.newFixedThreadPool(50); // 创建一个固定的线程池,线程数量为50        for (int i = 0; i < 1000; i++) {            service.submit(new Task()); // 提交1000个任务到线程池中执行        }        service.shutdown(); // 关闭线程池,等待所有任务完成    }    private static class Task implements Runnable {        @Override        public void run() {            try {                semaphore.acquire(); // 请求信号灯,等待许可                System.out.println(Thread.currentThread().getName() + "拿到了信号灯,开始执行");                Thread.sleep(2000); // 模拟耗时操作                System.out.println(Thread.currentThread().getName() + "执行完毕,归还信号灯");                semaphore.release(); // 释放信号灯,允许其他线程通过            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

二、CountDownLatch(倒计时锁)

CountDownLatch是一个用于线程间有序执行的工具。它允许一个线程或多个线程等待其他线程完成特定任务后再继续执行。CountDownLatch的默认行为是只能使用一次,但如果需要多次使用,可以使用CyclicBarrier。

使用场景:
  • 任务启动顺序控制:CountDownLatch可以用来控制多个线程的启动顺序。例如,主线程可以启动多个子线程,并等待它们完成后再继续执行。
  • 资源释放顺序:CountDownLatch还可以用来控制资源的释放顺序。例如,某个资源可能需要在另一个资源释放后才能被使用。
示例代码:
public class CountDownLatchDemo {    private static CountDownLatch countDownLatch = new CountDownLatch(3);    public static void main(String[] args) throws InterruptedException {        // 创建三个任务,每个任务都会等待CountDownLatch的完成        for (int i = 0; i < 3; i++) {            new Thread(new Task("任务" + (i + 1), countDownLatch)).start();        }        System.out.println("等待三个任务完成");        countDownLatch.await(); // 等待所有任务完成        System.out.println("所有任务已经完成");    }    private static class Task implements Runnable {        private String taskName;        private CountDownLatch countDownLatch;        public Task(String taskName, CountDownLatch countDownLatch) {            this.taskName = taskName;            this.countDownLatch = countDownLatch;        }        @Override        public void run() {            System.out.println("任务" + taskName + "开始执行");            try {                Thread.sleep(1000); // 模拟耗时操作                System.out.println("任务" + taskName + "已经完成");                countDownLatch.countDown(); // 倒计时减一,当倒计时减到零时,等待线程才会继续            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

三、CyclicBarrier(循环栅栏)

CyclicBarrier是一种可以多次使用的栅栏,它支持线程间的协作。与CountDownLatch不同,CyclicBarrier可以多次重复使用,适用于需要多次等待其他线程完成的场景。

使用场景:
  • 循环任务协作:CyclicBarrier适用于需要多次等待其他线程完成任务的情况。例如,多个线程需要轮流执行任务,每个任务完成后等待其他线程完成。
  • 资源循环使用:CyclicBarrier还可以用来管理资源的循环使用。例如,资源可能需要在多个阶段被多次使用,每个阶段等待其他线程完成后才能继续。
示例代码:
public class CyclicBarrierDemo {    public static void main(String[] args) throws Exception {        CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new Runnable() {            @Override            public void run() {                System.out.println("有3个线程已经到达,准备出发");            }        });        for (int i = 0; i < 6; i++) {            new Thread(new Task(i + 1, cyclicBarrier)).start();        }    }    private static class Task implements Runnable {        private int id;        private CyclicBarrier cyclicBarrier;        public Task(int id, CyclicBarrier cyclicBarrier) {            this.id = id;            this.cyclicBarrier = cyclicBarrier;        }        @Override        public void run() {            System.out.println("员工" + id + "现在从大门出发,前往自行车驿站");            try {                Thread.sleep((long) (Math.random() * 10000));                System.out.println("员工" + id + "到了自行车驿站,开始等待其他人到达");                cyclicBarrier.await();                System.out.println("员工" + id + "已经骑车出发,前往终点");            } catch (InterruptedException e) {                e.printStackTrace();            } catch (BrokenBarrierException e) {                e.printStackTrace();            }        }    }}

四、Lock(锁)

Lock是一种更高级的同步机制,它提供了与synchronized方法类似的功能,但具有更高的灵活性。Lock可以配置为公平锁、非公平锁或重入锁等。

使用场景:
  • 替代synchronized方法:Lock可以用来替代synchronized方法,提供更细粒度的同步控制。
  • 复杂的同步逻辑:Lock允许开发者根据具体需求定义同步逻辑,适用于复杂的多线程场景。
示例代码:
public class LockDemo {    private static Lock lock = new ReentrantLock(); // 使用可重入锁    public static void main(String[] args) throws InterruptedException {        for (int i = 0; i < 3; i++) {            new Thread(new Runnable() {                @Override                public void run() {                    try {                        lock.lock(); // 获取锁                        System.out.println("线程" + Thread.currentThread().getName() + "进入了同步区域");                        Thread.sleep(1000); // 模拟耗时操作                        System.out.println("线程" + Thread.currentThread().getName() + "离开了同步区域");                        lock.unlock(); // 释放锁                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }).start();        }    }}

五、Condition(条件)

Condition是一种基于对象的条件等待机制,它与Lock结合使用,提供更灵活的同步控制。Condition允许线程在获得锁的情况下等待某些条件成立,否则进入等待状态。

使用场景:
  • 复杂的条件等待:Condition允许开发者在获得锁的情况下,等待某些条件成立,这比传统的wait/notify机制更灵活。
  • 多线程协作:Condition可以用来管理多线程间的协作,适用于需要复杂条件等待的场景。
示例代码:
public class ConditionDemo {    private static Lock lock = new ReentrantLock();    private static Condition condition = lock.newCondition();    public static void main(String[] args) throws InterruptedException {        for (int i = 0; i < 3; i++) {            new Thread(new Runnable() {                @Override                public void run() {                    try {                        lock.lock(); // 获取锁                        System.out.println("线程" + Thread.currentThread().getName() + "进入了同步区域");                        condition.await(); // 等待条件成立                        System.out.println("线程" + Thread.currentThread().getName() + "通过了条件等待");                        lock.unlock(); // 释放锁                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }).start();        }    }}

六、总结

以上是Java多线程编程中常用的多线程控制工具的简要介绍。每种工具都有其适用的场景和特点,选择合适的工具能够更好地实现多线程编程中的同步与协作需求。在实际开发中,需要根据具体的业务需求选择合适的多线程控制工具,并正确地使用这些工具来保证程序的正确性和高效性。

转载地址:http://mywwz.baihongyu.com/

你可能感兴趣的文章
Netty工作笔记0060---Tcp长连接和短连接_Http长连接和短连接_UDP长连接和短连接
查看>>
Netty工作笔记0063---WebSocket长连接开发2
查看>>
Netty工作笔记0070---Protobuf使用案例Codec使用
查看>>
Netty工作笔记0077---handler链调用机制实例4
查看>>
Netty工作笔记0084---通过自定义协议解决粘包拆包问题2
查看>>
Netty工作笔记0085---TCP粘包拆包内容梳理
查看>>
Netty常用组件一
查看>>
Netty常见组件二
查看>>
netty底层源码探究:启动流程;EventLoop中的selector、线程、任务队列;监听处理accept、read事件流程;
查看>>
Netty心跳检测机制
查看>>
Netty核心模块组件
查看>>
Netty框架内的宝藏:ByteBuf
查看>>
Netty框架的服务端开发中创建EventLoopGroup对象时线程数量源码解析
查看>>
Netty源码—2.Reactor线程模型一
查看>>
Netty源码—3.Reactor线程模型三
查看>>
Netty源码—4.客户端接入流程一
查看>>
Netty源码—4.客户端接入流程二
查看>>
Netty源码—5.Pipeline和Handler一
查看>>
Netty源码—5.Pipeline和Handler二
查看>>
Netty源码—6.ByteBuf原理一
查看>>