一、概述
- 在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化(偏向锁、轻量级锁CAS)之后,有些情况下它并不那么重了。
- Java SE1.6为了减少获得锁和释放锁所带来的性能消耗,引入了“偏向锁”和“轻量级锁”,所以在Java SE1.6里锁一共有四种状态,无锁状态,偏向锁状态,轻量级锁状态和重量级锁状态,它会随着竞争情况逐渐升级。锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。
二、用法
- 实例方法:锁住整个方法,整个方法都需要同步。
- 静态方法:锁住整个方法,整个方法都需要同步。访问,所有对象实例上的线程都需要同步,这个同步静态方法,已经和类绑定。
- 实例方法中的同步块:只锁同步块,方法中其余地方线程可以并发执行。
- 静态方法中的同步块:只锁同步块,方法中其余地方线程可以并发执行。
三、注意事项
静态方法中的同步块,只能锁class对象
synchronized (SuspendTest.class)
和静态引用成员变量,不能锁非静态实例对象例如:synchronized (this)
,编译不通过。-
实例方法中的同步块,既能锁住class对象和静态引用成员变量,也可以锁对象实例。
- 锁住class对象或静态引用成员变量:所有对象实例上面的线程都需要同步执行。访问,所有对象实例上的线程都需要同步,这个同步静态代码块,已经和类绑定。
- 锁住对象实例: 不同对象实例上面的线程互不干扰,可以并发执行。
总之,只要synchronized和Class对象或者static扯上关系,访问,所有对象实例上的线程都需要同步。
四、测试代码
package test;
import java.util.concurrent.LinkedTransferQueue;
public class SuspendTest {
private static void getSome(){
//静态同步块,只能锁class,不可以锁实例
synchronized (SuspendTest.class){
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void setSome(){
//只有同步块需要线程同步执行,同步口外面的可以并发执行
//System.out.println(Thread.currentThread().getName());
synchronized (this){
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SuspendTest suspendTest = new SuspendTest();
suspendTest.test();
//suspendTest.testStatic();
SuspendTest suspendTest1 = new SuspendTest();
suspendTest1.test();
//suspendTest1.testStatic();
}
public void test(){
new Thread(()->{setSome();}).start();
new Thread(()->{setSome();}).start();
new Thread(()->{setSome();}).start();
}
public static void testStatic(){
new Thread(()->{getSome();}).start();
new Thread(()->{getSome();}).start();
new Thread(()->{getSome();}).start();
}
}