1synchronized同步方法
(1)synchronized取得的锁都是对象锁,而不是把一段代码或方法当作锁。
如果多个线程访问多个对象,则jvm会创建多个锁。
(2)脏读
赋值同步,取值不同步。
当线程a调用anyObject对象加入的synchronized关键字的x方法时,a线程就获得了x方法所在对象的锁,所以其他线程必须等a线程执行完毕才可以调用anyObject中加synchronized的方法,但b线程可以随意调用其他的非synchronized同步方法。
(3)synchronized锁重入
线程获取了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的。
当存在父子类继承关系时,子类可以通过“可重入锁”调用父类的同步方法。
(4)出现异常,锁自动释放
当一个线程执行的代码出现异常时,其所持有的锁会自动释放。
(5)同步不具有继承性
比如,父类的serviceMethod()方法有synchronized关键字修饰,子类的serviceMethod()方法没有synchronized关键字修饰,多个线程在调用子类的serviceMethod()方法时异步执行。
2synchronized同步语句块
(1)synchroninzed(this)同步代码块
用关键字synchronized声明方法在某些情况下是有弊端的,比如a线程调用同步方法执行一个长时间的任务,那么b线程则必须等待比较长的时间。这可以使用synchronized同步代码块解决:
synchronized(this){..}
当一个线程访问object的一个synchronized同步代码块时,另一个线程仍然可以访问该object对象中的非synchronized(this)同步代码块。
不在synchronized块中就是异步执行,在synchronized代码块中就是同步执行。
synchronized(this)代码块仍是对当前对象加锁,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块的访问将被阻塞。
synchronized方法的对象监视器是当前对象,synchronized(this)同步代码块的对象监视器也是当前对象。
(2)synchronized(非this对象)
synchronized(非this对象)同步代码块是对某个对象加锁。也就是说对象监视器是某个对象。
锁非this对象的优点:如果在一个类中有很多个synchronized方法,这时虽然能实现同步,但会受到阻塞。如果使用同步代码块锁非this对象,则synchronized(非this)代码块中的程序与同步方法是异步的,不与其他锁this同步方法争抢this锁,则可大大提高运行效率。
对象监视器相同,就会同步。
例如:synchronized(非this对象x)同步代码块,执行他的线程和执行x对象中synchronized同步方法,或x对象里面的synchronized(this)代码块呈同步效果。
(3)synchronized还可以应用在static静态方法上,此时对象监视器就是该*.java对应的class类。
class锁可以对类的所有对象起作用。
同步代码块synchronized(class)的作用和synchronized static 方法的作用一样。
(4)数据类型string的常量池特性
将synchronized(string)同步块与String联合使用,要注意常量池带来的一些意外。
例如:
String a="a";
String b="a";
System.out.println(a==b);//true
如果用相同字符串做锁,则视为一个锁,因此一般不使用string作为锁对象。
(5)死锁
线程互相持有对方的锁,等待对方释放。不使用嵌套的synchronized代码结构也会出现死锁,与嵌套不嵌套无关。
可以使用jdk自带的工具来监测是否有死锁的现象。
jps查看java进程号
jstack -l 进程号 监测是否有死锁。
(6)锁对象的改变
主要看线程之间争抢的锁是不是同一个。
如果锁的对象不变,对象的属性被改变,运行的结果还是同步的。
3volatile关键字
作用:强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。
(1)volatile解决的是变量在多个线程之间的可见性。
(2)synchronized解决的是多个线程之间访问资源的同步性。它还具有将线程工作内存中的私有变量与公共内存中的变量同步的功能。
关键字synchronized可以保证在同一时刻,只有一个线程可以执行某一个方法或某一个代码块。它包含两个特征:互斥性和可见性。同步synchronized不仅可以解决一个线程看到对象处于不一致的状态,还可以保证进入同步方法或同步代码块的每个线程,都看到由同一个锁保护之前所有的修改效果(每个线程进入同步方法后,都能看到被同一个锁保护前的所有修改状态)。