首页 文章 精选 留言 我的

精选列表

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

中英文代码对比系列之Java一例

这个系列将对同一段代码进行中文命名和英文命名两个版本的比较. 目的包括, 演示中文命名, 发现命名时可能遇到的问题, 探讨代码风格(中文命名的'套路')等. 示例中的命名风格仅基于个人非常有限的实践, 希望抛砖引玉. 不在讨论范围内的是: 中英文代码的可读性孰高孰低. 个人相信用英文和中文都能写出可读性很好的代码. 区别仅在于母语不同的开发者对哪个版本更敏感, 读写维护起来更省工. 原代码本身的优化/风格问题. 如果认为有更有代表性的代码, 请不吝推荐. 代码输入的便捷性. 前作对在代码中使用中文命名的质疑与回应'中文输入太慢, 降低开发效率'一节中有所涉及, 打算另开题探讨. 下面一段代码选自Clean Code: A Handbook of Agile Software Craftsmanship一书, 19页. 已经经过了作者的命名改进. 由于本人也没有看过全书, 如果此段代码在此书之后某节仍有命名改进, 请麻烦指出. public List<Cell> getFlaggedCells() { List<Cell> flaggedCells = new ArrayList<Cell>(); for (Cell cell : gameBoard) if (cell.isFlagged()) flaggedCells.add(cell); return flaggedCells; } 中文命名版: public List<格类> 取被标的格() { List<格类> 被标的格 = new ArrayList<格类>(); for (格类 某格 : 雷区) if (某格.是被标的()) 被标的格.add(某格); return 被标的格; } 这里触及了几处典型的中文命名问题. 首先, 是没有大小写区分类和变量名(Cell cell). 个人采用的是在类名中使用后缀'类'. 暂时没有发现有类名本身就用'类'结尾的情况(那样会出现XXX类类的命名), 即使如此, 应该可以用改为类型结尾来规避(就成为XXX类型类). 变量名也与类名有一致之处, 就是所有关于格类的变量都用xx格命名, 与英文命名方法相同. 下面, 是单复数的区别. flaggedCells是个List, 它用复数命名的意思是"可能包含多个格". 而实际上这个变量可能只包含一个格. 中文中的名词不分单复数, 正好符合"这个变量有可能含有单个或多个元素"这个语义. 因此命名为被标的格感觉可行. 假如语义需要强调有多个(不可能只有单个或没有), 可以考虑加上修饰如多个前缀等等. 相比之下, 如何在for循环中表示单数有些麻烦. 这个for循环的语义大概是:for one/each cell in the gameboard, if the cell is flagged, add the cell to..., 原代码中没对one/each cell和the cell作出区分. 对应中文大约是对于雷区中的每一格, 如果这一格是被标的, 就把这一格加到.... 同样也很难在代码中用一个词体现每一格和这一格这两个有差别的语义. 另外可能的命名有一格, 每格, 此格, 在不需突出单数的情况下直接用格等等. get前缀的方法名, 中文采用了对应的取, 用动词短语可以和变量名区分, 这和英文命名类似. 有个潜在的技术问题, 就是Bean中get的特殊规则. 个人认为在这种情况下可以采用混用, 即get被标的格. 这个Spring Boot的演示程序中就是如此. is前缀的方法名, 一般认为是返回布尔值的方法. 这里采用的命名是被标的是个很直白的对应命名. 既保留了是作为表示返回布尔值, 也保留了被动语态. 个人觉得稍显累赘, 但与其他命名一致(取'被标的'格, '被标的'格), 并且易于使用在其他情况, 比如isRunning->是运行中的, isTerriblyDamaged->是被严重损坏的等等. 不失为一种可行的风格. 这里原本使用了是被标记的, 但感觉去掉一字也可以接受. 此外, gameBoard没有采用直译, 而是用雷区, 因为这个代码在原作中是假想从一个mine sweeper game(扫雷游戏)中选取的, 因此感觉比较适合. 当然, 原代码中gameBoard也可以用mineField使这一段单独出来的代码更有语境. 但正如开头声明, 此文并不对中英文代码之间的可读性进行比较. 这里也就不拘泥于找到gameBoard的对应中文了. 再次欢迎各种推敲. 2017-11-09

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

【iOS】用strong和weak来修饰成员变量的对比

对于纯代码布局,用@property声明成员变量时,我是很自然的用strong来修饰的。然后突然有人问我用weak来修饰可不可以,我第一反应是不可以,因为用weak来修饰,初始化过后就会被释放掉,就算我第一句写了初始化的方法,立即执行addSubView也是没办法将其添加上去的。xcode也给出了很明确的警告:Assigning retained object to weak variable; object will be released after assignment。然后他又给分析了一堆内存管理的东西,得出的结论是可以。 由于我之前确实没有思考过这个问题,对于这个结论我也是半信半疑,然后我就写了个demo来验证。自己写demo之前我想起了之前看过的一些代码,有些成员变量是用weak修饰的,初始化方法是将一个临时变量赋值给它,然后将它加到父View上,我很不理解这样为什么这样写,直接用strong修饰,然后来个懒加载初始化不是更好?或者直接初始化然后再添加?这样算起来还少一行代码。。。 写demo的过程中我又发现了一些其他的东西,首先我声明两个成员变量,一个strong修饰,一个weak修饰。 @interface ViewController () @property(nonatomic,strong) UILabel * strongLabel; @property(nonatomic,weak) UILabel * weakLabel; @end strongLabel使用懒加载来初始化: -(UILabel *)strongLabel{ if (!_strongLabel) { _strongLabel = [[UILabel alloc] initWithFrame:CGRectMake(30, 100, 200, 60)]; _strongLabel.backgroundColor = [UIColor orangeColor]; _strongLabel.text = @"我是strong"; _strongLabel.textAlignment = NSTextAlignmentCenter; } return _strongLabel; } weakLabel直接用上面的懒加载方式来初始化 -(UILabel *)weakLabel{ if (!_weakLabel) { //警告:Assigning retained object to weak variable; object will be released after assignment _weakLabel = [[UILabel alloc] initWithFrame:CGRectMake(30, 120, 200, 60)]; _weakLabel.backgroundColor = [UIColor cyanColor]; _weakLabel.text = @"我是weak"; _weakLabel.textAlignment = NSTextAlignmentCenter; } return _weakLabel; } 测试表明在viewDidLoad方法中调用addSubView方法来添加self.weakLabel时,self.weakLabel依然为nil,添加无效。 改进后的weakLabel的懒加载初始化方式: -(UILabel *)weakLabel{ if (!_weakLabel) { UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(30, 170, 200, 60)]; label.backgroundColor = [UIColor cyanColor]; label.text = @"我是weak"; label.textAlignment = NSTextAlignmentCenter; _weakLabel = label; [self.view addSubview:self.weakLabel];//如果不加这一句,下面return的时候_weakLabel依然为nil } return _weakLabel; } 这样写之后在viewDidLoad方法中调用addSubView方法来添加self.weakLabel可以添加成功。 还有就是不用懒加载的方式来初始化weakLabel: -(void)initWeakLabel{ // _weakLabel = [[UILabel alloc] initWithFrame:CGRectMake(30, 170, 200, 60)]; // _weakLabel.backgroundColor = [UIColor cyanColor]; // _weakLabel.text = @"我是weak"; // _weakLabel.textAlignment = NSTextAlignmentCenter; // [self.view addSubview:_weakLabel]; UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(30, 170, 200, 60)]; label.backgroundColor = [UIColor cyanColor]; label.text = @"我是weak"; label.textAlignment = NSTextAlignmentCenter; _weakLabel = label; [self.view addSubview:self.weakLabel];//如果不加这一句,在别处调用_weakLabel时依然为nil } 用weak修饰的成员变量初始化之后就会被释放掉,所以注释部分的代码是无法添加成功的。 以上这些验证了用weak修饰UI成员变量是可以的,但是就这些而言,我也确实找不到用weak相较用strong而言更好的理由。因为这两个label添加成功之后唯一的区别就是strongLabel的引用计数为2,weakLabel的引用计数为1,如果后期它们再做同样的操作,我实在是想不出会有什么情况strongLabel会出现内存泄漏而weakLabel不会出现内存泄漏的情况。 后来我试着对这两个Label进行删除和再添加的操作,还发现了weak修饰还是要谨慎使用,因为如果weak修饰的UI不是用懒加载来初始化的话,一旦weakLabel被removeFromSuperView了,就会变成nil,再次添加将无法显示。虽然对这样的操作更多的人会选择hide属性,但是有些场景还是需要用到removeFromSuperView。 最后结论如下: UI成员变量可以用weak来修饰。 用weak修饰的UI成员变量初始化方法与strong修饰的成员变量初始化方法不同(可参考上面的代码,如有更好的初始化方法也可分享)。 用weak修饰的成员变量调用removeFromSuperView会变成nil,strong修饰的调用removeFromSuperView变量地址不变。 再次调用被移除的weakLabel无任何效果(除非使用懒加载的方法初始化,此时weakLabel与之前被移除的weakLabel内存地址不同),再次调用被移除的strongLabel可以添加成功,地址与原地址相同。 也就是对于strongLabel而言,removeFromSuperView只是从View上移除它,但是它依然在内存中。而对于weakLabel而言,removeFromSuperView不仅是从View上移除它,也会从内存中删除它。 如果某个UI移除后需要在某种条件下再次显示初始的情况可以使用weak来修饰。 常用xib的可能比较熟悉weak,因为关联生成的成员变量都默认是weak修饰的,也可以选择strong,因为将Label拖到xib上就已经完成了初始化和添加的操作,此时的Label引用计数为1,相当于纯代码的初始化和添加。以上得出的结论同样适用于xib上的UI,所以在用xib布局时,要注意移除在添加的操作。 面试的时候经常被问strong、weak、copy等属性的区别,这个验证也很好的证明了weak修饰的变量被释放后会被置为nil,再次访问不会发生崩溃的特性。 最后我又验证了一下用weak来修饰数组,直接初始化依然无法调用,初始化一个变量,然后将该变量赋值为weak数组后是可以的。 验证的测试demo地址为:https://github.com/zhanqin/strongAndWeak。

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

01.Java基础(多线程回顾,对比Linux多线程)

两个线程间通信,实现交替打印 public class Thread1 { public static void main(String[] args) { final Printer printer = new Printer(); new Thread(new Runnable() { @Override public void run() { while(true){ try { printer.print1(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true){ try { printer.print2(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); } } /** * 等待唤醒机制,两个线程间通信 * @author renzhenming * */ class Printer{ private int flag = 1; public void print1() throws InterruptedException{ synchronized(this){ if (flag !=1) { /** * obj.wait():该方法的调用,使得调用该方法的执行线程(T1)放弃obj的对象锁并阻塞, * 直到别的线程调用了obj的notifyAll方法、或者别的线程调用了obj的notify方法且JVM选择唤醒(T1), * 被唤醒的线程(T1)依旧阻塞在wait方法中,与其它的线程一起争夺obj的对象锁, * 直到它再次获得了obj的对象锁之后,才能从wait方法中返回。 * (除了notify方法,wait还有带有时间参数的版本,在等待了超过所设时间之后, * T1线程一样会被唤醒,进入到争夺obj对象锁的行列;另外中断可以直接跳出wait方法) * * 1.在同步代码块中,用哪个对象锁就用哪个对象调用wait方法, * 2.为什么wait和notify这些方法要定义在Object类中?因为锁对象可以是任意对象,那么任意对象的类都是Object的子类,Object是任意类的基类,所以将方法定义在Object这个类中就会让任意对象对其进行调用 * sleep和wait方法的区别:a.sleep在同步代码块或同步函数中,不释放锁,(睡着了也会抱着锁睡),wait相反会释放锁 b.sleep方法必须传入参数,参数就是时间,时间到了自动醒来,wait方法可以传入时间参数,也可以不传入时间参数,如果给wait方法传入时间参数,用法与sleep相似,时间到了就停止等待(通常都是用没有参数的wait方法) */ this.wait(); } System.out.print("y"); System.out.print("i"); System.out.print("n"); System.out.print("g"); System.out.print("z"); System.out.print("i"); System.out.print("\r\n"); flag = 2; /** * obj.notify():该方法的调用,会从所有正在等待obj对象锁的线程中,唤醒其中的一个(选择算法依赖于不同实现), * 被唤醒的线程此时加入到了obj对象锁的争夺之中,然而该notify方法的执行线程此时并未释放obj的对象锁, * 而是离开synchronized代码块时释放。因此在notify方法之后,synchronized代码块结束之前, * 所有其他被唤醒的,等待obj对象锁的线程依旧被阻塞。 */ this.notify(); } } public void print2() throws InterruptedException{ synchronized (this) { if (flag != 2) { wait(); } System.out.print("z"); System.out.print("h"); System.out.print("e"); System.out.print("n"); System.out.print("m"); System.out.print("i"); System.out.print("n"); System.out.print("g"); System.out.print("\r\n"); flag = 1; notify(); } } } 打印结果 yingzi zhenming yingzi zhenming yingzi zhenming yingzi zhenming yingzi zhenming yingzi zhenming yingzi zhenming yingzi zhenming yingzi zhenming ... 三个线程或三个以上通信(试错,期待的结果是逐条打印,实际结果看下边) 按照上边的方式,代码如下: public class Thread1 { public static void main(String[] args) { final Printer printer = new Printer(); new Thread(new Runnable() { @Override public void run() { while(true){ try { printer.print1(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true){ try { printer.print2(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true){ try { printer.print3(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); } } /** * 等待唤醒机制,两个线程间通信 * @author renzhenming * */ class Printer{ private int flag = 1; public void print1() throws InterruptedException{ synchronized(this){ if (flag !=1) { /** * obj.wait():该方法的调用,使得调用该方法的执行线程(T1)放弃obj的对象锁并阻塞, * 直到别的线程调用了obj的notifyAll方法、或者别的线程调用了obj的notify方法且JVM选择唤醒(T1), * 被唤醒的线程(T1)依旧阻塞在wait方法中,与其它的线程一起争夺obj的对象锁, * 直到它再次获得了obj的对象锁之后,才能从wait方法中返回。 * (除了notify方法,wait还有带有时间参数的版本,在等待了超过所设时间之后, * T1线程一样会被唤醒,进入到争夺obj对象锁的行列;另外中断可以直接跳出wait方法) */ this.wait(); } System.out.print("y"); System.out.print("i"); System.out.print("n"); System.out.print("g"); System.out.print("z"); System.out.print("i"); System.out.print("\r\n"); flag = 2; /** * obj.notify():该方法的调用,会从所有正在等待obj对象锁的线程中,唤醒其中的一个(选择算法依赖于不同实现), * 被唤醒的线程此时加入到了obj对象锁的争夺之中,然而该notify方法的执行线程此时并未释放obj的对象锁, * 而是离开synchronized代码块时释放。因此在notify方法之后,synchronized代码块结束之前, * 所有其他被唤醒的,等待obj对象锁的线程依旧被阻塞。 */ this.notify(); } } public void print2() throws InterruptedException{ synchronized (this) { if (flag != 2) { wait(); } System.out.print("z"); System.out.print("h"); System.out.print("e"); System.out.print("n"); System.out.print("m"); System.out.print("i"); System.out.print("n"); System.out.print("g"); System.out.print("\r\n"); flag = 3; notify(); } } public void print3() throws InterruptedException{ synchronized (this) { if (flag != 3) { wait(); } System.out.print("f"); System.out.print("a"); System.out.print("l"); System.out.print("l"); System.out.print("i"); System.out.print("n"); System.out.print("l"); System.out.print("o"); System.out.print("v"); System.out.print("e"); System.out.print("\r\n"); flag = 1; notify(); } } } 结果: zhenming yingzi zhenming yingzi zhenming yingzi zhenming yingzi zhenming yingzi zhenming yingzi zhenming fallinlove zhenming ... 为什么会出现上边的情况?我们极端分析一下,假设,第一个回合中,首先执行的是第2和第3个线程,也就是print2 print3方法,此时,由于flag不满足执行条件,两个线程都进入了等待状态,然后执行print1打印了一条,设置flag=2,然后notify,此时通常疏忽的开发人员可能会想当然的认为,flag=2 了,那么理所当然应该唤醒线程2了,应该打印print2了,事实上并非如此,由于notify是随机唤醒一个线程,那么它可能唤醒2 也可能唤醒3,假设此时被唤醒的线程是3,由于if语句的特性,不会重新判断执行条件,而是在哪里等待,在哪里醒来,于是直接跳过了判断语句执行了print3的打印内容,所以就出现了这种情况 针对这种问题,我们尝试用while代替if做条件判断,while是循环判断,每次判断都会判断标记,我们对程序做修改后如下: public class Thread1 { public static void main(String[] args) { final Printer printer = new Printer(); new Thread(new Runnable() { @Override public void run() { while(true){ try { printer.print1(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true){ try { printer.print2(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true){ try { printer.print3(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); } } /** * 等待唤醒机制,两个线程间通信 * @author renzhenming * */ class Printer{ private int flag = 1; public void print1() throws InterruptedException{ synchronized(this){ while (flag !=1) { /** * obj.wait():该方法的调用,使得调用该方法的执行线程(T1)放弃obj的对象锁并阻塞, * 直到别的线程调用了obj的notifyAll方法、或者别的线程调用了obj的notify方法且JVM选择唤醒(T1), * 被唤醒的线程(T1)依旧阻塞在wait方法中,与其它的线程一起争夺obj的对象锁, * 直到它再次获得了obj的对象锁之后,才能从wait方法中返回。 * (除了notify方法,wait还有带有时间参数的版本,在等待了超过所设时间之后, * T1线程一样会被唤醒,进入到争夺obj对象锁的行列;另外中断可以直接跳出wait方法) */ this.wait(); } System.out.print("y"); System.out.print("i"); System.out.print("n"); System.out.print("g"); System.out.print("z"); System.out.print("i"); System.out.print("\r\n"); flag = 2; /** * obj.notify():该方法的调用,会从所有正在等待obj对象锁的线程中,唤醒其中的一个(选择算法依赖于不同实现), * 被唤醒的线程此时加入到了obj对象锁的争夺之中,然而该notify方法的执行线程此时并未释放obj的对象锁, * 而是离开synchronized代码块时释放。因此在notify方法之后,synchronized代码块结束之前, * 所有其他被唤醒的,等待obj对象锁的线程依旧被阻塞。 */ this.notify(); } } public void print2() throws InterruptedException{ synchronized (this) { while (flag != 2) { wait(); } System.out.print("z"); System.out.print("h"); System.out.print("e"); System.out.print("n"); System.out.print("m"); System.out.print("i"); System.out.print("n"); System.out.print("g"); System.out.print("\r\n"); flag = 3; notify(); } } public void print3() throws InterruptedException{ synchronized (this) { while (flag != 3) { wait(); } System.out.print("f"); System.out.print("a"); System.out.print("l"); System.out.print("l"); System.out.print("i"); System.out.print("n"); System.out.print("l"); System.out.print("o"); System.out.print("v"); System.out.print("e"); System.out.print("\r\n"); flag = 1; notify(); } } } 更离谱的问题出现,打印结果: yingzi zhenming fallinlove 三个线程在执行一次之后就全部停了,或者说全部进入了等待状态,为什么会出现这一现象? 假设程序执行开始,先执行了线程2线程3,由于flag条件不满足,两个线程都进入等待状态,此时线程1开始执行,设置flag=2,执行完毕notify唤醒一个线程,并且由于自身条件也陷入等待状态,假设先唤醒的是线程3,由于flag值不对,线程3仍然处于等待状态,这种情况下,三个线程全部陷入等待状态 notify随机唤醒一个线程,是导致这一问题出现的原因,那么可否唤醒全部线程呢, notifyall就出现了,notifyAll可以唤醒全部线程,然后根据条件的判断执行相应的线程,但是这样做是由弊端的,那就是每次都要将所有线程唤醒,这是JDK1.5之前的处理办法,JDK1.5有新的方法解决这一问题 public class Thread1 { public static void main(String[] args) { final Printer printer = new Printer(); new Thread(new Runnable() { @Override public void run() { while(true){ try { printer.print1(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true){ try { printer.print2(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true){ try { printer.print3(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); } } /** * 等待唤醒机制,两个线程间通信 * @author renzhenming * */ class Printer{ private int flag = 1; public void print1() throws InterruptedException{ synchronized(this){ while (flag !=1) { /** * obj.wait():该方法的调用,使得调用该方法的执行线程(T1)放弃obj的对象锁并阻塞, * 直到别的线程调用了obj的notifyAll方法、或者别的线程调用了obj的notify方法且JVM选择唤醒(T1), * 被唤醒的线程(T1)依旧阻塞在wait方法中,与其它的线程一起争夺obj的对象锁, * 直到它再次获得了obj的对象锁之后,才能从wait方法中返回。 * (除了notify方法,wait还有带有时间参数的版本,在等待了超过所设时间之后, * T1线程一样会被唤醒,进入到争夺obj对象锁的行列;另外中断可以直接跳出wait方法) */ this.wait(); } System.out.print("y"); System.out.print("i"); System.out.print("n"); System.out.print("g"); System.out.print("z"); System.out.print("i"); System.out.print("\r\n"); flag = 2; /** * obj.notify():该方法的调用,会从所有正在等待obj对象锁的线程中,唤醒其中的一个(选择算法依赖于不同实现), * 被唤醒的线程此时加入到了obj对象锁的争夺之中,然而该notify方法的执行线程此时并未释放obj的对象锁, * 而是离开synchronized代码块时释放。因此在notify方法之后,synchronized代码块结束之前, * 所有其他被唤醒的,等待obj对象锁的线程依旧被阻塞。 */ this.notifyAll(); } } public void print2() throws InterruptedException{ synchronized (this) { while (flag != 2) { wait(); } System.out.print("z"); System.out.print("h"); System.out.print("e"); System.out.print("n"); System.out.print("m"); System.out.print("i"); System.out.print("n"); System.out.print("g"); System.out.print("\r\n"); flag = 3; notifyAll(); } } public void print3() throws InterruptedException{ synchronized (this) { while (flag != 3) { wait(); } System.out.print("f"); System.out.print("a"); System.out.print("l"); System.out.print("l"); System.out.print("i"); System.out.print("n"); System.out.print("l"); System.out.print("o"); System.out.print("v"); System.out.print("e"); System.out.print("\r\n"); flag = 1; notifyAll(); } } } 结果: yingzi zhenming fallinlove yingzi zhenming fallinlove yingzi zhenming fallinlove yingzi zhenming fallinlove yingzi zhenming fallinlove ... JDK1.5互斥锁 所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源的访问. 而现在, Lock提供了比synchronized机制更广泛的锁定操作, Lock和synchronized机制的主要区别: synchronized机制提供了对与每个对象相关的隐式监视器锁的访问, 并强制所有锁获取和释放均要出现在一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是隐式的, 只要线程运行的代码超出了synchronized语句块范围, 锁就会被释放. 而Lock机制必须显式的调用Lock对象的unlock()方法才能释放锁, 这为获取锁和释放锁不出现在同一个块结构中, 以及以更自由的顺序释放锁提供了可能。 import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Thread1 { public static void main(String[] args) { final Printer printer = new Printer(); new Thread(new Runnable() { @Override public void run() { while (true) { try { printer.print1(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while (true) { try { printer.print2(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while (true) { try { printer.print3(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); } } /** * 等待唤醒机制,互斥锁 * * @author renzhenming * */ class Printer { ReentrantLock r = new ReentrantLock(); Condition c1 = r.newCondition(); Condition c2 = r.newCondition(); Condition c3 = r.newCondition(); private int flag = 1; public void print1() throws InterruptedException { r.lock(); if (flag != 1) { c1.await(); } System.out.print("y"); System.out.print("i"); System.out.print("n"); System.out.print("g"); System.out.print("z"); System.out.print("i"); System.out.print("\r\n"); flag = 2; c2.signal(); r.unlock(); } public void print2() throws InterruptedException { r.lock(); if (flag != 2) { c2.await(); } System.out.print("z"); System.out.print("h"); System.out.print("e"); System.out.print("n"); System.out.print("m"); System.out.print("i"); System.out.print("n"); System.out.print("g"); System.out.print("\r\n"); flag = 3; c3.signal(); r.unlock(); } public void print3() throws InterruptedException { r.lock(); if (flag != 3) { c3.await(); } System.out.print("f"); System.out.print("a"); System.out.print("l"); System.out.print("l"); System.out.print("i"); System.out.print("n"); System.out.print("l"); System.out.print("o"); System.out.print("v"); System.out.print("e"); System.out.print("\r\n"); flag = 1; c1.signal(); r.unlock(); } } 结果,按照唤醒顺序执行线程,不再需要使用while判断,if即可 fallinlove yingzi zhenming fallinlove yingzi zhenming fallinlove yingzi zhenming fallinlove yingzi zhenming fallinlove yingzi zhenming fallinlove yingzi zhenming fallinlove yingzi zhenming ...

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

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

Sublime Text

Sublime Text

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

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册