(欢迎关注微信公众号:深入Java底层)
synchronized同步方法/synchronized(this)同步代码块
·同一时间只有一个线程可以执行synchronized同步方法/synchronized(this)同步代码块中的代码。
·对其他synchronized同步方法或synchronized(this)同步代码调用呈阻塞状态。
synchronized(非this对象x)同步代码块
·当多个线程同时执行synchronized(x){}同步代码块时呈同步效果。
·当其他线程执行x对象中synchronized同步方法时呈同步效果。
·当其他线程执行x对象方法里面的synchronized(this)代码块时也呈现同步效果。
但需要注意:如果其他线程调用不加synchronized关键字的方法时,还是异步调用。
synchronized锁重入
关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的。这也证明在一个synchronized方法/块的内部调用本类的其他synchronized方法/块时,是永远可以得到锁的。
当存在父子类继承关系时,子类是完全可以通过“可重入锁”调用父类的同步方法的。
出现异常,锁自动释放
当一个线程执行的代码出现异常时,其持有的锁会自动释放。
同步不具有继承性
同步不能继承,要想子类方法也有同步效果,子类方法也要添加synchronized关键字。
数据类型String的常量特性
在JVM中具有String常量池缓存的功能,同步synchronized代码块中使用String作为锁对象时,两个string锁对象有可能是同一个锁对象。在大多数的情况下,同步synchronized代码块都不使用String作为锁对象,而改用其他,比如new Object()实例化一个Object对象,但它并不放入缓存中,这样就是两个不同的锁对象。
同步synchronized方法无限等待与解决
一个类中多个同步方法,如果其中一个同步方法无限循环,其他同步方法将无限等待,永远得不到运行的机会。这时就可以使用同步块来解决这样的问题,同步块之间使用不同的对象锁。
多线程的死锁
Java线程死锁是一个经典的多线程问题,因为不同的线程都在互相等待对方释放锁,从而导致所有的任务都无法继续完成,出现死锁。在多线程技术中,“死锁”是必须避免的,因为这会造成线程的“假死”。
可以使用JDK自带的工具来监测是否有死锁的现象。首先进入CMD工具,再进入JDK安装文件夹中的bin目录,执行jps命令,如2-57所示。
得到运行的线程Run的id值是3244。再执行jstack命令,查看结果,如果2-58所示。
监测出有死锁现象,如图2-59所示。
内置类与静态内置类
实例化内置类:
PublicClasspublicClass = new PublicClass ();
PrivateClass privateClass = publicClass.new PrivateClass();
实例化静态内置类:
PrivateClass privateClass = new PrivateClass();
在内置类中持有不同锁的同步方法,异步执行;同步代码块synchronized(class2)对内置类class2上锁后,其他线程只能以同步的方法调用class2中的静态同步方法。
锁对象的改变
·如果多个线程共同争抢的锁资源在逻辑处理过程发生了改变,那么线程之间是异步的。(如果多个线程同时获取锁,锁对象的值有可能还没来得及改变,就已经完成锁争抢的动作,此时线程之间还是同步运行)
·只要对象不变,即使对象的属性被改变,运行结果还是同步的。
(欢迎关注微信公众号:深入Java底层)