注:可以这样理解,因为synchronized(x)中,对象监视器是x,即是将锁加载了x上,那么对于x对象来说,他本身已经被上锁,则他的synchronized方法与synchronized(this)自然与synchronized(x){}呈同步效果。
关键字synchronized还可以应用在static静态方法上,如果这样写,那是对当前的*.java文件对应的Class类进行加锁。
注:synchronized关键字修饰static静态方法是给Class类加锁,而synchronized关键字加到非static静态方法上是给对象上锁。
Class锁可以对类的所以对象实例起作用,使其代码的执行是同步的(但是注意如果有代码块锁的是Class的实例对象,则是不同的锁,是对象锁,此时的代码与Class锁的代码执行是异步的)。
synchronized(class)代码块的作用与synchronized static方法的作用是一样的。
这一节其实比较难理解,但是如果你能够理解锁的对象之间的区别或许就能更好的理解为什么同步为什么异步。
由于String具有常量池缓存的功能,将synchronized(String)同步代码块与String联合起来使用时,要注意常量池带来的影响。
若有String A = String B = “相同的字符串”; 则synchronized(A)与synchronized(B)就具有一把相同的锁,就有可能出现阻塞的现象。
同步方法很容易造成死循环。
比如在synchronized方法中出现无限循环时,这是就陷入了阻塞,其他想要获取该对象同步锁的方法都无法获取该对象的同步锁了。其实是为下一节死锁做个铺垫。
死锁是一个经典的多线程问题,因为不同的线程都在等待根本不可能释放的锁(),从而导致所有的任务都无法进行。在多线程技术中死锁是必须避免的,因为这会造成线程的“假死”。
死锁是程序设计的bug,在设计程序的过程中要避免出现互相持有对方锁的情况。
死锁出现的核心:存在互相等待对方释放锁就有可能出现死锁。
就是写了内部类跟静态内部类怎么创建。
当内部类中有两个不同方法,且使用的是不同的锁时,这两个方法的运行结果是异步的。
实际上内部类中的同步效果也符合2.8的三个结论。
在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程间就是同步的;如果持有不同的锁对象,这些线程之间就是异步的。
第二小节小总结:实际上第二章后半部分一直在针对不用的使用情况去印证前面已经证实过的结论(也就是说没有太多卵用,核心的东西都在前八个知识点)。
第三节volatile关键字
注:关键字volatile的主要作用是使变量在多个线程间可见
什么都没说。写了个死循环的案例,可能是这本书是一本很基础的书吧。。
有时候看得我挺无语的
在线程中若有变量private Boolean isRunning = true;该变量存在于公共堆栈及线程的私有堆栈中。此时将JVM设置为-server时,为了线程的运行的效率,线程一直在私有堆栈中取得isRunning的值,若修改isRunning,更新的会是公共堆栈中的isRunning的值,所以会导致出现异常。
问题的实质是:私有堆栈的值和公共堆栈中不同步造成的,使用volatile关键字可以解决,使线程访问isRunning时强制从公共堆栈中取值。
volatile关键字增加了实例变量在多个线程之间的可见性,但volatile关键字很致命的一点在于其不支持原子性。
synchronized与volatile的比较:
volatile是线程同步的轻量级实现,性能比synchronized要好,并且volatile只能修饰变量,而synchronized可以修饰方法与代码块。
多线程访问volatile不会发生阻塞,而synchronized会出现阻塞。