首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

swift4.1 系统学习十一 闭包

// // main.swift // swift11(闭包) // // Created by iOS on 2018/10/10. // Copyright © 2018年 weiman. All rights reserved. // import Foundation /* 闭包 闭包是swift中比较重要的一部分内容,也是个人认为比较难以理解的内容,也可能是之前没有 细细的研究的缘故。 1.闭包的概念 闭包是将一个函数与执行环境存放在一起的一条记录。 名字绑定:当闭包被创建的时候,它会将它所在的函数中的局部对象与它自己的执行环境中的对象名做一个值或者 引用的关联映射。这就是“名字绑定”。 捕获:如果闭包访问了它所在函数的局部对象,那么我们称它“捕获”了该局部对象。 注意: 由于闭包有自己的执行环境,我们称为上下文,因此即便当它所在的函数被返回值后,该闭包依然能正常调用。 问题:那么闭包什么时候被销毁呢? 我们之前提到过,捕获外部函数局部对象的嵌套函数属于命名闭包,它也是个闭包。但是,函数、闭包和方法还是各自独立的更好些。 */ do { func foo() { print("这是一个函数") } g_func = foo CTest() //打印结果: 这是一个函数 func boo() { var a = 10 func inner() { print("这是一个内部函数") } g_func = inner CTest() func closure() { a += 10 print("closure a = \(a)") } // 报错:A C function pointer cannot be formed from a local function that captures context // 函数指针不能指向闭包 //g_func = closure g_func = { print("哈哈哈哈哈") } CTest() struct MyStruct { let a: Int, b: Double func method() { print("a = \(a), b = \(b)") } static func typeMethod() { print("这是一个结构体") } } // 报错:A C function pointer can only be formed from a reference to a 'func' or a literal closure // g_func = MyStruct.typeMethod let obj = MyStruct(a: 10, b: 100.0) // 报错:A C function pointer can only be formed from a reference to a 'func' or a literal closure // g_func = obj.method } boo() /* 小结: 一个C函数指针对象只能指向一般的函数,包括不捕获其外部函数局部对象的嵌套函数,以及不捕获其外部函数局部对象的闭包。 */ } // 2. 闭包的定义与调用 /* 在swift中,一个闭包又称为“闭包表达式”。 基本语法形式: _ = { (参数1: 参数类型, 参数2: 参数类型....) -> 返回值类型 in 闭包执行代码 } */ do { _ = { () -> Void in print("这是一个简单的无参数的无返回值的闭包") } _ = { (a: Int) -> Void in print("这是一个有参数,无返回值的闭包,参数:a = \(a)") } // 有参数,有返回值的闭包,返回值是 () -> Void _ = { (a: Int, b: Int) -> () -> Void in let sum = a + b var x = sum * 2 return { () -> Void in print("sum = \(sum)") x += sum } } } // 闭包的调用 // 闭包的调用与函数的调用一样,可以直接在闭包表达式的后面使用函数调用操作符,形成完整的函数调用表达式。 do { print("\n ----------- 闭包的调用-------------") _ = { () -> Void in print("无参数无返回值的闭包") } () _ = { (a: Int) -> Void in print("a = \(a)") } (10) } // 3. 闭包表达式的简略表达(重点哟) /* 因为swift语言强大的类型推导特性,我们可以将闭包表达式简化。 */ do { //1.缺省返回类型的表达式 /* 如果一个函数的返回类型省略,则函数的返回类型就是Void,但是,如果闭包的返回类型省略, 则不一定是Void。 */ let ref = { (a: Int, b: Int) in return a + b } print("value = \(ref(1, 2))") // 结果: value = 3 // 上述闭包表达式中,返回值就是 (Int, Int)-> Int 类型 //2.缺省参数类型的闭包表达式 // swift不仅能够推导出闭包的返回值类型,还能推导出参数的类型,因此,闭包的形参也是可以省略的。 // 并且小括号也是可以省略的。如果闭包形参列表的圆括号省略了,那么每个形参的类型都必须缺省。 var ref2: (Int, Int) -> Int = { a, b in return a + b } print("1: \(ref2(2, 3))") ref2 = { a, b -> Int in return a + b } print("2: \(ref2(4, 6))") ref2 = { (a, b: Int) in return a + b } print("3: \(ref2(4, 5))") // 3. 缺省return关键字 // 如果闭包表达式中其执行语句只有一个单独的 return语句构成,那么关键字return也可以缺省 let ref3: (Int, Int) -> Int = { a, b in a + b } print("value = \(ref3(1, 1))") // 返回值是一个元组的第二个元素 print("\n") let ref4 = { (a: Int) -> Int in (print("a = \(a)"), a + 1).1 } print("value2 = \(ref4(3))") // 4. 省略 in 关键字 // 如果一个闭包确定其每个形参的类型以及返回类型,那么该表达式中连 in 关键字都能缺省。 // 当我们要引用其形参时使用 $ 符号加上形参索引:第一个形参的索引值为0,第二个索引值为1,后续参数 // 依次类推。 print("\n") var r: (Int, Int) -> Int = { $0 + $1 } print("value: \(r(3, 3))") let r2 = { print("hello") } r2() r = { print("第一个参数: \($0)") print("第二个参数: \($1)") return $0 + $1 } print("result: \(r(5, 8))") let r3: (Int) -> Void = { print("参数: \($0)") let a = $0 * $0 print("a = \(a)") } r3(5) } // 4. 尾随闭包 /* 如果一个闭包表达式作为函数调用的最后一个实参,那么我们可以采用“尾随闭包”语法糖。 */ do { print("\n ----------尾随闭包---------------") func foo(_ a: Int, callback: (Int) -> Void) { callback(a) } foo(10) { (aa) in print("参数是 \(aa)") } //或者简写 foo(12, callback: { print("参数: \($0)")}) //尾随闭包, 这个时候callback标签必须省略 foo(14){ print("参数是: \($0)") } func boo (_ a: Int, _ b: Int, callback: ((Int, Int) -> Int)?) { if let callback = callback { let value = callback(a, b) print("value = \(value)") } } boo(2, 3) { (a: Int, b: Int) -> Int in return a * a + b * b } } // 5. 捕获局部对象与闭包执行上下文 // 闭包所捕获的对象是按照引用进行捕获的,同时闭包本身是一个引用对象。 do { print("\n ----------捕获局部对象与闭包执行上下文---------------") var a = [1, 2, 3] var b = a a[0] += 10 print("a = \(a)") // 结果: a = [11, 2, 3] func foo() { var a = 10 let closure = { print("a = \(a)") } closure() a += 10 closure() } foo() /* 结果: a = 10 a = 20 */ func boo() -> () -> Void { var x = 10 return { x += 10 print("x = \(x)") } } var closure = boo() var ref = closure closure() ref() closure() /* 结果: x = 20 x = 30 x = 40 */ // 重新赋值后再次调用 ref = boo() closure() ref() /* 结果: x = 50 x = 20 */ /* 小结: 上述实例证明了闭包属于引用类型,闭包所捕获的外部局部对象也是以引用的方式 捕获的。 */ } // 6. 逃逸闭包 /* 如果我们定义了一个函数,它有一个形参为函数类型,如果在此函数中将通过异步的方式调用该函数引用对象, 那么我们需要将此函数类型声明为“逃逸的”,以表示该函数类型的形参对象将可能在函数调用操作结束后的某一 时刻才会被调用。 */ do { print("\n --------逃逸闭包----------") var ref: (() -> Void)! func foo(closure: @escaping () -> Void) { ref = closure } foo { print("你好") } ref() } // 7. 自动闭包 /* 自动闭包也是swift中的一个语法糖。如果一个函数的某个形参为函数类型,并且不含有任何形参,那么我们 就可以将此参数声明为“自动闭包”。 */ do { print("\n---------自动闭包----------") func foo(closure: () -> Void) { closure() } foo { print("简单的闭包") } func boo(auto closure: @autoclosure () -> Void) { closure() } boo(auto: print("这是个自动闭包")) func doo() { let a = 1, b = -1 func isLarger(compare: @autoclosure () -> Bool) -> Bool { return compare() } let result = isLarger(compare: a > b) print("result: \(result)") } doo() /* 小结: 不推荐各位在制作公共的API的时候使用自动闭包。 */ } 辅助文件: // // Test.h // swift11(闭包) // // Created by iOS on 2018/10/10. // Copyright © 2018年 weiman. All rights reserved. // #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface Test : NSObject extern void (^ _Nullable g_block)(void); // 指向函数的指针 extern void (* _Nullable g_func)(void); extern void CTest(void); @end NS_ASSUME_NONNULL_END // // Test.m // swift11(闭包) // // Created by iOS on 2018/10/10. // Copyright © 2018年 weiman. All rights reserved. // #import "Test.h" @implementation Test void (^ g_block)(void) = NULL; void (* g_func)(void) = NULL; void CTest(void) { if (g_block != NULL) { g_block(); } if (g_func != NULL) { g_func(); } } @end

优秀的个人博客,低调大师

python和机器学习代码中遇到的问题

1.pycharm运行pyspark代码,没有Hadoop环境 Could not locate executable null\bin\winutils.exe in the Hadoop binaries. 解决方案 解压一份Hadoop包,配置HADOOP_HOME并加入Path变量中。 2.读取文件编码问题 SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \xXX escape 错误代码 文件路径用的是斜杠 lines = spark.textFile("C:\xin\code\temp\ratings.dat") 解决方案 应该用反斜杠 lines = spark.textFile("C:/xin/code/temp/ratings.dat") 3.Rating参数个数问题 __new__() takes 4 positional arguments but 5 were given代码 model = ALS.train(training, rank=50, iterations=10, lambda_=0.01) 报错信息 File "C:\ProgramData\Anaconda3\lib\site-packages\pyspark\mllib\recommendation.py", line 233, in <lambda> ratings = ratings.map(lambda x: Rating(*x)) TypeError: __new__() takes 4 positional arguments but 5 were given 报错说,要4个参数,但是给你5个。 看源码 ( File "C:ProgramDataAnaconda3libsite-packagespysparkmllibrecommendation.py", line 30) class Rating(namedtuple("Rating", ["user", "product", "rating"])): 这里其实要的是3个参数。 4.同时存在Python2和Python3,运行pyspark报错 报错信息 File "/usr/lib/python2.7/site-packages/pyspark-2.3.1-py2.7.egg/pyspark/worker.py", line 176, in main ("%d.%d" % sys.version_info[:2], version)) Exception: Python in worker has different version 2.7 than that in driver 3.6, PySpark cannot run with different minor versions.Please check environment variables PYSPARK_PYTHON and PYSPARK_DRIVER_PYTHON are correctly set. 解决方案 在"~/.bashrc"添加配置(重启虚拟机)。 export PATH="/root/anaconda3/bin:$PATH"

优秀的个人博客,低调大师

深入学习Lock锁(3)——重入锁ReentrantLock

1.简介 重入锁ReentrantLock,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁。除此之外,该锁还支持获取锁时的公平和非公平性选择。 所谓重复加锁,就是某个线程中当调用lock方法对临界区加锁之后,在临界区中再次调用lock方法来进行加锁,如果同步组件不支持重复加锁就会对自己(当前线程)阻塞。而synchronized关键字隐式的支持重进入,比如一个synchronized修饰的递归方法,在方法执行时,执行线程在获取了锁之后仍能连续多次地获得该锁。 关于锁获取的公平性问题,如果在绝对时间上,先对锁进行获取的请求一定先被满足,那么这个锁是公平的,反之,是不公平的。公平的获取锁,也就是等待时间最长的线程最优先获取锁,也可以说锁获取是顺序的。ReentrantLock提供了一个构造函数,能够控制锁是否是公平的。但是也因此导致公平的锁机制往往没有非公平的效率高,但是,并不是任何场景都是以TPS作为唯一的指标,公平锁能够减少“饥饿”发生的概率,等待越久的请求越是能够得到优先满足。 2.实现重进入 1.重进入是指任意线程在获取到锁之后能够再次获取该锁而不会被锁所阻塞,该特性的实现需要解决以下两个问题: 1)线程再次获取锁。锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取。 2)锁的最终释放。线程重复n次获取了锁,随后在第n次释放该锁后,其他线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁 被释放时,计数自减,当计数等于0时表示锁已经成功释放。 2.代码实现分析:ReentrantLock是通过组合自定义同步器来实现锁的获取与释放,以非公平性(默认的)实现代码为例 final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } 该方法增加了再次获取同步状态的处理逻辑:通过判断当前线程是否为获取锁的线程来 决定获取操作是否成功,如果是获取锁的线程再次请求,则将同步状态值进行增加并返回 true,表示获取同步状态成功。 成功获取锁的线程再次获取锁,只是增加了同步状态值,这也就要求ReentrantLock在释放同步状态时减少同步状态值。释放代码如下 protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; } 3.公平性与非公平性获取锁的区别 1.代码实现分析: 公平性与否是针对获取锁而言的,如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序,也就是FIFO。对于非公平锁,只要CAS设置同步状态成功,则表示当前线程获取了锁,而公平锁则不同。 protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } } 该方法与nonfairTryAcquire(int acquires)比较,唯一不同的位置为判断条件多了 hasQueuedPredecessors()方法,即加入了同步队列中当前节点是否有前驱节点的判断,如果该方法返回true,则表示有线程比当前线程更早地请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。测试代码: import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TestReentrantLock { private static ReentrantLock1 lock1=new ReentrantLock1(true); private static ReentrantLock1 lock2=new ReentrantLock1(false); static class ReentrantLock1 extends ReentrantLock{ public ReentrantLock1(boolean isfair){ super(isfair); } public Collection<Thread> getQueuedThreads(){ ArrayList arrayList = new ArrayList<Thread>(super.getQueuedThreads()); Collections.reverse(arrayList); return arrayList; } } static class TestThread extends Thread{ ReentrantLock1 lock; int index; public TestThread(ReentrantLock1 l,int i){ lock=l; index=i; } public String toString(){ return index+""; } public void run(){ lock.lock(); try { System.out.println("线程"+Thread.currentThread()+"持有锁:" +"等待队列"+lock.getQueuedThreads()); } catch (Exception e) { // TODO: handle exception }finally { System.out.println("释放"); lock.unlock(); } lock.lock(); try { System.out.println("线程"+Thread.currentThread()+"持有锁:" +"等待队列"+lock.getQueuedThreads()); } catch (Exception e) { // TODO: handle exception }finally { System.out.println("释放"); lock.unlock(); } } } static void testLock(ReentrantLock1 l){ TestThread t1=new TestThread(l,1); TestThread t2=new TestThread(l,2); TestThread t3=new TestThread(l,3); TestThread t4=new TestThread(l,4); t1.start(); t2.start(); t3.start(); t4.start(); } public static void main(String[] args) { testLock(lock1);//测试公平锁 //testLock(lock2);//测试不公平锁 } } 测试显示结果是随机的,对于已加入同步队列的线程执行确实是依据FIFO规则,但是线程加入同步队列的次序是由CPU调配的。 公平锁测试结果显示: 线程1持有锁:等待队列[2, 3, 4] 释放 线程2持有锁:等待队列[3, 4, 1] 释放 线程3持有锁:等待队列[4, 1, 2] 释放 线程4持有锁:等待队列[1, 2, 3] 释放 线程1持有锁:等待队列[2, 3, 4] 释放 线程2持有锁:等待队列[3, 4] 释放 线程3持有锁:等待队列[4] 释放 线程4持有锁:等待队列[] 释放 不公平锁测试结果 线程1持有锁:等待队列[2, 3, 4] 释放 线程1持有锁:等待队列[2, 3, 4] 释放 线程2持有锁:等待队列[3, 4] 释放 线程2持有锁:等待队列[3, 4] 释放 线程3持有锁:等待队列[4] 释放 线程3持有锁:等待队列[4] 释放 线程4持有锁:等待队列[] 释放 线程4持有锁:等待队列[] 释放 对比测试结果可以知道,公平性锁每次都是从同步队列中的第一个节点获取到锁,而非公平性锁出现了一个线程连续获取锁的情况。 为什么会出现线程连续获取锁的情况呢?在nonfairTryAcquire(int acquires)方法中,当一个线程请求锁时,只要获取了同步状态即成功获取锁。在这个前提下,刚释放锁的线程再次获取同步状态的几率会非常大,使得其他线程只能在同步队列中等待。而之所以将非公平锁设为默认,就是因为它减少了线程间的切换,比如该测试中,非公平锁会切换4次,而公平锁则会切换8次,这就会带来极大地开销。但是非公平锁也会造成线程”饥饿”的问题。

优秀的个人博客,低调大师

深入学习Lock锁(2)——LockSupport工具类

在同步组件中,当需要阻塞或唤醒一个线程的时候,都会使用LockSupport工具类来完成相应 工作。LockSupport定义了一组的公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能,而LockSupport也成为构建同步组件的基础工具。 LockSupport定义了一组以park开头的方法用来阻塞当前线程,以及unpark(Thread thread) 方法来唤醒一个被阻塞的线程。 public static void park():阻塞当前线程,如果调用unpark(Thread thread) 方法解除阻塞或者中断线程该方法才能返回。 public static void parkNanos( long nanos):在park()方法的基础上增加了超时返回条件。 public static void parkUntil(long deadline):阻塞当前线程,直到从1970年到deadline毫秒数的某一时刻 public static void unpark(Thread thread):唤醒处于阻塞状态的线程。 在Java 6中,LockSupport增加了park(Object blocker)、parkNanos(Object blocker,long nanos) 和parkUntil(Object blocker,long deadline)3个方法,用于实现阻塞当前线程的功能,其中参数 blocker是用来标识当前线程在等待的对象(以下称为阻塞对象),该对象主要用于问题排查和系统监控。因为当线程阻塞(使用synchronized关键字)在一个对象上时,通过线程dump能够 查看到该线程的阻塞对象,方便问题定位,而Java 5推出的Lock等并发工具时却遗漏了这一 点,致使在线程dump时无法提供阻塞对象的信息。因此,在Java 6中,LockSupport新增了上述3 个含有阻塞对象的park方法,用以替代原有的park方法。

优秀的个人博客,低调大师

【C语言】学习笔记10——其他数据结构

1. 联合:能在同一内存空间中存储不同的数据类型(不是同时存储)。典型用法是,设计一种表以存储既无规律、事先也不知道顺序的混合类型。 下面是一个代表及的联合模板 union hold { int digit; double bigfl; char letter; } 根据以上形式声明的类型可以存储一个int类型或一个double类型或一个char类型的值。 2. 枚举类型:可以使用枚举类型声明符号名称来表示整型常量。 使用 enum 关键字, 可以创建一个新“类型”并指定它可具有的值。 enum spectrum {red, orange. yellow, green. blue, violet}; enum spectrum color; 枚举符是int类型,但是枚举变量可以是任意整数类型,前提是该整数类型足够长,可以存储所有的枚举常量。比如 spectrum 的枚举符范围是0~5, 所以编译器可以用 unsigned char 来表示color变量 C允许枚举变量使用 ++ 运算符,但是C++标准不允许 3. 在枚举声明中,可以为枚举常量指定整数值 enum levels {low = 100, medium = 500, high = 2000} 如果只给一个枚举常量赋值,后面的常量没有被赋值 enum feline(cat, lynx = 10, puma, tiger) // cat = 0, lynx = 10, puma = 11, tiger = 12 4. typedef: 类似别名,或者说更接近于包装

优秀的个人博客,低调大师

java多线程系列:通过对战游戏学习CyclicBarrier

CyclicBarrier是java.util.concurrent包下面的一个工具类,字面意思是可循环使用(Cyclic)的屏障(Barrier),通过它可以实现让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,所有被屏障拦截的线程才会继续执行。 这篇文章将介绍CyclicBarrier这个同步工具类的以下几点 通过案例分析 两种不同构造函数测试 CyclicBarrier和CountDownLatch的区别 await方法及源码分析。 需求 继上一篇CountDownLatch模拟游戏加载后,现在用户点击开始按钮后,需要匹配包括自己在内的五个玩家才能开始游戏,匹配玩家成功后进入到选择角色阶段。当5位玩家角色都选择完毕后,开始进入游戏。进入游戏时需要加载相关的数据,待全部玩家都加载完毕后正式开始游戏。 解决方案 从需求中可以知道,想要开始游戏需要经过三个阶段,分别是 匹配玩家 选择角色 加载数据 在这三个阶段中,都需要互相等待对方完成才能继续进入下个阶段。 这时可以采用CyclicBarrier来作为各个阶段的节点,等待其他玩家到达,在进入下个阶段。 定义继承Runnable的类 这里名称就叫做StartGame,包含两个属性 private String player; private CyclicBarrier barrier; 通过构造函数初始化两个属性 public StartGame(String player, CyclicBarrier barrier) { this.player = player; this.barrier = barrier; } run方法如下 public void run() { try { System.out.println(this.getPlayer()+" 开始匹配玩家..."); findOtherPlayer(); barrier.await(); System.out.println(this.getPlayer()+" 进行选择角色..."); choiceRole(); System.out.println(this.getPlayer()+" 角色选择完毕等待其他玩家..."); barrier.await(); System.out.println(this.getPlayer()+" 开始游戏,进行游戏加载..."); loading(); System.out.println(this.getPlayer()+" 游戏加载完毕等待其他玩家加载完成..."); barrier.await(); start(); } catch (Exception e){ e.printStackTrace(); } } 其他的方法findOtherPlayer()、choiceRole()等待使用 Thread.sleep() 来模拟花费时间 编写测试代码 CyclicBarrier有两个构造函数,如下 public CyclicBarrier(int parties) {} public CyclicBarrier(int parties, Runnable barrierAction) {} 先来看看一个参数的构造函数 CyclicBarrier(int parties) public static void main(String[] args) throws IOException { CyclicBarrier barrier = new CyclicBarrier(5); Thread player1 = new Thread(new StartGame("1",barrier)); Thread player2 = new Thread(new StartGame("2",barrier)); Thread player3 = new Thread(new StartGame("3",barrier)); Thread player4 = new Thread(new StartGame("4",barrier)); Thread player5 = new Thread(new StartGame("5",barrier)); player1.start(); player2.start(); player3.start(); player4.start(); player5.start(); System.in.read(); } 测试结果如下 CyclicBarrier(int parties, Runnable barrierAction) CyclicBarrier barrier = new CyclicBarrier(5); 替换为 CyclicBarrier barrier = new CyclicBarrier(5, () -> { try { System.out.println("阶段完成,等待2秒..."); Thread.sleep(2000); System.out.println("进入下个阶段..."); } catch (InterruptedException e) { e.printStackTrace(); } }); 再来看看效果 可以看到在到达某个节点时,会执行实例化CyclicBarrier时传入的Runnable对象。而且每一次到达都会执行一次。 CyclicBarrier和CountDownLatch的区别 CountDownLatch CyclicBarrier 计数为0时,无法重置 计数达到0时,计数置为传入的值重新开始 调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响 调用await()方法计数减一,若减一后的值不等于0,则线程阻塞 不可重复使用 可重复使用 await方法 public int await(){} public int await(long timeout, TimeUnit unit){} 无参的await方法这里就不做介绍了,主要介绍下有参的await方法。 有参的await方法传入两个参数,一个是时间、另一个是时间单位 当调用有参的await方法时会出现下方两个异常 java.util.concurrent.TimeoutException java.util.concurrent.BrokenBarrierException TimeoutException异常是指调用await方法后等待时间超过传入的时间,此时会将CyclicBarrier的状态变成broken,其他调用await方法将会抛出BrokenBarrierException异常,这时的CyclicBarrier将变得不可用,需要调用reset()方法重置CyclicBarrier的状态。 为什么这么说? 源码分析一波就可以看出来了 不管是有参还是无参的await方法都是调用CyclicBarrier的dowait(boolean timed, long nanos)方法,这个方法代码太长了,截取部分贴出来 private int dowait(boolean timed, long nanos){ //加锁、try catch代码 final Generation g = generation; //判断栅栏的状态 if (g.broken) throw new BrokenBarrierException(); //...省略 int index = --count; //(index == 0) 时的代码,省略 for (;;) { try { if (!timed) trip.await(); else if (nanos > 0L) nanos = trip.awaitNanos(nanos); } catch (InterruptedException ie) {} //判断栅栏的状态 if (g.broken) throw new BrokenBarrierException(); if (g != generation) return index; //判断是否是定时的,且已经超时了 if (timed && nanos <= 0L) { //打破栅栏的状态 breakBarrier(); throw new TimeoutException(); } } //解锁 } 在代码的尾部进行判断当前等待是否已经超时,如果是会调用breakBarrier()方法,且抛出TimeoutException异常,下面是breakBarrier()的代码 private void breakBarrier() { generation.broken = true; count = parties; trip.signalAll(); } 代码中将broken状态置为true,表示当前栅栏移除损坏状态,且重置栅栏数量,然后唤醒其他等待的线程。此时被唤醒的线程或者其他线程进入dowait方法时,都会抛出BrokenBarrierException异常 案例源代码地址:https://github.com/rainbowda/learnWay/tree/master/learnConcurrency/src/main/java/com/learnConcurrency/utils/cyclicBarrier 觉得不错的点个Star,谢谢

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册