闭锁与栅栏是在多线程编程中的概念,因为在多线程中,我们不能控制线程的执行状态,所以给线程加锁,让其按照我们的想法有秩序的执行。
闭锁
CountDownLatch,实例化时需要传入一个int类型的数字(count),意为等待count个线程完成之后才能执行下一步动作。
如今天要做的事情是吃晚饭,再去散步。假设11个人相约晚饭后一起去散步,我们得等11个人全都吃完晚饭了才能出发去散步。简而言之就是做了才到达某一种状态。
栅栏
CyclicBarrier,实例化时需要传入一个int类型的数字(parties),意为等待parties个线程都准备就绪后才能执行自己的任务。
如今天要做的事情是吃晚饭,8个人约好一起去某餐厅吃饭,得等到人齐了才能去吃饭。简而言之就是到达某种状态后一起做。
闭锁 CountDownLatch
package com.test; import java.util.ArrayList; import java.util.List; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CountDownLatch; public class Test { public static void main(String[] args) { CountDownLatch latch = new CountDownLatch(3); // 模拟三个任务 List<String> jobs = new ArrayList<String>(); jobs.add("first"); jobs.add("second"); jobs.add("third"); // 循环执行任务 for (String job : jobs) { new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " : 进入run方法"); latch.countDown(); System.out.println(Thread.currentThread().getName() + " : 执行" + job); } }).start(); } try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } // 任务都执行完后才执行 System.out.println("回到main线程"); } }
执行结果:
Thread-1 : 进入run方法
Thread-2 : 进入run方法
Thread-2 : 执行third
Thread-0 : 进入run方法
Thread-1 : 执行second
Thread-0 : 执行first
回到main线程
通过执行结果可看出,当所有线程都执行完后才能回到主线程继续执行后面的输出。
栅栏 CyclicBarrier
package com.test; import java.util.ArrayList; import java.util.List; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class Test { public static void main(String[] args) { CyclicBarrier barrier = new CyclicBarrier(3); // 模拟创建三个任务 List<String> jobs = new ArrayList<String>(); jobs.add("first"); jobs.add("second"); jobs.add("third"); //循环执行任务 for (String job : jobs) { new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " : 进入run方法"); try { // 等待 barrier.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " : 执行" + job); } }).start(); } } }
执行结果:
Thread-1 : 进入run方法 Thread-2 : 进入run方法 Thread-0 : 进入run方法 Thread-0 : 执行first Thread-1 : 执行second Thread-2 : 执行third
通过执行结果可看出,当所有线程都执行都进入到run方法后,才能继续执行自己内部的方法。
到此这篇关于Java并发编程之闭锁与栅栏的实现的文章就介绍到这了,更多相关Java 闭锁与栅栏内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
时间:2020-04-30
栅栏类似闭锁,但是它们是有区别的. 1.闭锁用来等待事件,而栅栏用于等待其他线程.什么意思呢?就是说闭锁用来等待的事件就是countDown事件,只有该countDown事件执行后所有之前在等待的线程才有可能继续执行;而栅栏没有类似countDown事件控制线程的执行,只有线程的await方法能控制等待的线程执行. 2.CyclicBarrier强调的是n个线程,大家相互等待,只要有一个没完成,所有人都得等着. 场景分析:10个人去春游,规定达到一个地点后才能继续前行.代码如下 复制代码 代码如
闭锁相当于一扇门,在闭锁到达结束状态之前,这扇门一直是关闭着的,没有任何线程可以通过,当到达结束状态时,这扇门才会打开并容许所有线程通过.它可以使一个或多个线程等待一组事件发生.闭锁状态包括一个计数器,初始化为一个正式,正数表示需要等待的事件数量.countDown方法递减计数器,表示一个事件已经发生,而await方法等待计数器到达0,表示等待的事件已经发生.CountDownLatch强调的是一个线程(或多个)需要等待另外的n个线程干完某件事情之后才能继续执行. 场景应用: 10个运动员准备赛
编写线程安全需要关心的: 1.共享的变量 2.可变的变量 共享意味着多个线程可以同时访问,可变意味着其值在生命周期可以改变. 例如以下count 变量: 复制代码 代码如下: //线程不安全的类 public class UnsafeCount { private int count = 0; //该变量是共享的 public void increase() { //这里没有同步机制,多个线程可以同时访问 count++; //该变量是可变的
定义:一个软件实体如类.模块和函数应该对扩展开放,对修改关闭. 问题由来:在软件的生命周期内,因为变化.升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试. 解决方案:当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化. 开闭原则是面向对象设计中最基础的设计原则,它指导我们如何建立稳定灵活的系统.开闭原则可能是设计模式六项原则中定义最模糊的一个了,它
ThreadLocal类可以理解为ThreadLocalVariable(线程局部变量),提供了get与set等访问接口或方法,这些方法为每个使用该变量的线程都存有一份独立的副本,因此get总是返回当前执行线程在调用set时设置的最新值.可以将ThreadLocal<T>视为 包含了Map<Thread,T>对象,保存了特定于该线程的值. 概括起来说,对于多线程资源共享的问题,同步机制采用了"以时间换空间"的方式,而ThreadLocal采用了"以空间
定义: Provide a surrogate or placeholder for another object to control access to it. 为其他对象一种代理以控制对这个对象的访问. 一般描述: 一般包含的三个角色:抽象主题.具体主题.代理主题. 抽象主题:是一个抽象类或接口,是一个普通的业务类型定义. 具体主题:业务逻辑的具体执行者 代理角色:负责对真是角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现. 通用类图: 通用代码: package Pro
Java并发编程:CountDownLatch与CyclicBarrier和Semaphore的实例详解 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法. 以下是本文目录大纲: 一.CountDownLatch用法 二.CyclicBarrier用法 三.Semaphore用法 若有不正之处请多多谅解,并欢迎批评指正. 一.CountDownLatch
Java并发编程(CyclicBarrier)实例详解 前言: 使用JAVA编写并发程序的时候,我们需要仔细去思考一下并发流程的控制,如何让各个线程之间协作完成某项工作.有时候,我们启动N个线程去做一件事情,只有当这N个线程都达到某一个临界点的时候,我们才能继续下面的工作,就是说如果这N个线程中的某一个线程先到达预先定义好的临界点,它必须等待其他N-1线程也到达这个临界点,接下来的工作才能继续,只要这N个线程中有1个线程没有到达所谓的临界点,其他线程就算抢先到达了临界点,也只能等待,只有所有这N
本文主要探究的是java并发编程callable与future的使用,分享了相关实例代码,具体介绍如下. 我们都知道实现多线程有2种方式,一种是继承Thread,一种是实现Runnable,但这2种方式都有一个缺陷,在任务完成后无法获取返回结果.要想获得返回结果,就得使用Callable,Callable任务可以有返回值,但是没法直接从Callable任务里获取返回值:想要获取Callabel任务的返回值,需要用到Future.所以Callable任务和Future模式,通常结合起来使用. 试想
java并发编程是java程序设计语言的一块重点,在大部分的业务场景中都需要并发编程. 比如:并发的去处理http请求,这样就可以使得一台机器同时处理多个请求,大大提高业务的响应效率,从而使用用户体验更加流畅. java如何并发编程,要注意以下几个方面: 1.java语言中的多线程操作:创建和启动线程的几种方式. 2.共享变量的同步问题,要保证线程安全,辨别哪些变量是线程安全的.那些变量是线程不安全的,对于不安全的变量我们要想办法让其同步,一般也就是加锁. 3.线程锁:包括方法锁和synchro
一.任务和执行策略之间的隐性耦合 Executor可以将任务的提交和任务的执行策略解耦 只有任务是同类型的且执行时间差别不大,才能发挥最大性能,否则,如将一些耗时长的任务和耗时短的任务放在一个线程池,除非线程池很大,否则会造成死锁等问题 1.线程饥饿死锁 类似于:将两个任务提交给一个单线程池,且两个任务之间相互依赖,一个任务等待另一个任务,则会发生死锁:表现为池不够 定义:某个任务必须等待池中其他任务的运行结果,有可能发生饥饿死锁 2.线程池大小 注意:线程池的大小还受其他的限制,如其他资源池: