[Java]线程和锁

0x00 线程调度

线程调度指的是系统为线程分配CPU使用权。分为两种:

  1. 协同式线程调度
    线程想用CPU多久就用多久,用完了才让给别的线程。实现简单,但容易发生进程阻塞。
  2. 抢占式线程调度
    可以用yield()让出使用权。并且可以设优先级。即便一个线程阻塞了,也不会导致进程阻塞。

0x01 (对象的)线程安全

指的是并发访问对象时不会进行额外的同步操作。比如Immutable的对象就是线程安全的。

0x02 线程安全的实现方法

1. 互斥同步(Mutual Exclusion & Synchronization)

又称阻塞同步。
同步是指多个线程并发访问共享数据时,保证同一时刻共享数据只被一个(使用信号量时对应:一些)线程使用。
互斥是手段,同步是目的。
在Java中,最基本的互斥同步手段就是synchronized关键字(除了synchronized之外,还可以使用ReentrentLock,重入锁)。

synchronized关键字在编译后会行程moniterenter和moniterexit两个字节码指令,这两个指令需要一个reference类型的参数来指明要加锁和解锁的对象。如果synchronized明确指定了对象参数,就用这个对象作为锁对象(所以会看到声明一个成员变量的数组作为锁对象);如果没有明确指定,就根据synchronized修饰的是实例方法还是类方法,取对应的对象实例或者Class对象作为锁对象。

有点像GC的引用计数算法

在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。

注意:

synchronized是一个重量级(heavyweight)的操作。

Java的线程是映射到操作系统的原生线程上的,阻塞或唤醒线程都需要CPU时间,帮助用户态和内核态之间转换,对于简单的同步块,有可能状态转换的时间比执行的时间还长。

0x02 非阻塞同步

从处理问题的方式上说,互斥同步属于一种悲观的并发策略。
随着硬件指令集的发展,我们有了另外一个选择:基于冲突检测的乐观并发策略,通俗地说,就是先进行操作,如果没有其他线程争用共享数据,那操作就成功了;

如果共享数据有争用,产生了冲突,那就再采取其他的补偿措施(最常见的补偿措施就是不断地重试,直到成功为止),这种乐观的并发策略的许多实现都不需要把线程挂起,因此这种同步操作称为非阻塞同步(Non-Blocking Synchronization)。

Ref:
http://blog.csdn.net/truelove12358/article/details/54963791
http://blog.csdn.net/qinjienj/article/details/7578582

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容