Java并发编程-学习笔记(一)

在最近的面试中,都被问到关于C++和Java并发的问题,然而直接懵逼,所以决心开始学习并发,以Java并发入手。

也不只是为了现在的面试,以后的工作更是少不了并发,提前预习罢了。


 

先说说被要求写代码的一道题吧。

发红包问题,一个红包先设定好钱数、分发的人数,然后由别人来抢,要求抢到红包的人数不能超过设定的人数,被抢到红包的金额之和不能超过限定的钱数。

如果不是面试官提醒,我都没想到这个要多线程处理,还以为难点在金额的随机算法上,并发的意识太薄弱了,恰恰随机算法却不是最重要的,重要的是保证多个人多线程访问money这个变量的时候,不会因为共享的存在导致出错。

下面是我重新写的代码。

 


 

竞态条件

当某个计算的正确性取决于多个线程的交替执行时序时,那么就会发生竞态条件。正确结果的获得要取决于运气。最常见的竞态条件类型就是“先检查后执行”操作,即依赖一个可能已经失效的数据来决定下一步要进行的动作。

在抢红包的例子中,就存在竞态条件:get的计算依赖于money,如果没有加同步限制或加锁,则可能出现这样的情况:线程A根据money计算出get_1,线程B又根据没有更新的money计算出get_2,再各自执行一步,money则有可能变成负数。

要保持状态的一致性,就需要在单个原子操作中更新所有相关的状态变量。

所以在这里,我们用同步代码块来保证同步,使状态的更新变成原子操作,而IO操作不涉及状态的改变且耗时大,所以不考虑同步,这也是不使用同步方法的原因。


 

内置锁

就是我在上面代码中使用的 synchronized关键字修饰的同步代码块,当用该关键字修饰方法时,就是一个横跨整个方法体的同步代码块。

同步代码块包括两部分:一个是作为锁的对象引用,一个作为有这个锁保护的代码块。同步代码块的锁就是方法调用所在的对象,静态的synchronized方法以Class对象作为锁。


重入

当某个线程请求一个由其他线程持有的锁时,该发出请求的线程就会阻塞,等待锁的释放。如果一个锁是可重入的,当某个线程试图获得一个由自己所持有的锁,那么这个请求将会成功。

内置锁就是可重入的。

重入意味着获取锁的操作粒度是“线程”,而不是“调用”。pthread(POSIX线程)互斥体的默认加锁行为不同,pthread互斥体的获取操作是以“调用”为粒度的。

发表评论

电子邮件地址不会被公开。 必填项已用*标注