一、基本概念
synchronized 是由 monitorenter / monitorexit 的指令实现的。Java 6之前完全是依赖操作系统的互斥锁。现在的JDK中,JVM对此进行了改进,提供了三种 monitor 的实现,偏斜锁(Biased Lock),轻量级锁,重量级锁 很大程度上的提高了性能。
升级降级:是JVM 对synchronized的优化,检测到不同的竞争状况,JVM会自动的切换到适合的锁,没有竞争出现的时候,默认出现的是 偏斜锁,JVM会采用CAS (Compare and swap)的方式, 在对象的头上的Mark Word 部分设置 线程的ID ,表示这个对象偏向于当前线程,并不涉及真正的互斥锁,使用偏斜锁可以降低无竞争的开销。若别的线程想锁定某个已经被偏斜过的对象。JVM就需要撤销偏斜锁。切换到轻量级锁实现,轻量级锁依赖于CAS操作Mark Word 来试图获得锁,若重试成功,就使用普通的轻量级锁,否则就使用重量级锁。降级也是确实会发生的,当JVM 进行入安全点(SafePoint)的时候,会检查是否有闲置的monitor来进行降级。
二、使用场景
//同步的方法
pubilc synchronized void test() {
}
//静态
pubilc static synchronized void test() {
}
//同步代码块上
public void test() {
synchronized(obj) {
System.out.println("===");
}
}
三、synxheonized (this) 和 synchronized(object) 区别
synchronized(object) 是包含 synchronized(this)的,
1.当两个线程同时执行一个 synchronized 的同步代码块的时候 ,同一个时间片内只允许执行一个线程, 另一个线程必须等到当前的线程执行完毕后才能执行。
2.当一个线程执行 synchronized 同步代码块的时候,就获得了对象锁。另一个线程可以执行 非 同步的方法,若另一个线程执行 同步代码快时,会被阻塞。
synchronized method :会获得所有的 synchronized 的对象锁,,也就是说一个线程在执行 同步代码块的时候,影响了其他线程对同步代码块的访问。
在 静态方法前加 synchronized :静态方法属于这个类,获取到的锁属于类的锁
在非静态方法前加 synchronized :属于当前对象的锁。
四、案例分析
第一个案例
Thread01 t01 = new Thread01(); //
System.out.println("synchronized 关键字使用 \n" +"--------------------------");
Thread ta = new Thread(t01,"A");
Thread tb = new Thread(t01,"B");
//谁抢到了 cpu 的执行权 ,谁就执行
ta.start();
tb.start();
private class Thread01 implements Runnable{
@Override
public void run() {
synchronized (this) {
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName()+" synchronized loop "+i);
}
}
}
}
执行结果:
synchronized 关键字使用
--------------------------
B synchronized loop 0
B synchronized loop 1
B synchronized loop 2
A synchronized loop 0
A synchronized loop 1
A synchronized loop 2
第二个案例
// 当一个线程在执行 同步代码块的时候,其他的线程必须等当前的线程执行完毕后才能执行。因为是非公平锁,其他的线程会争抢这个锁。
System.out.println("synchronized 关键字使用 \n" +"--------------------------");
Thread t02A = new Thread(new Runnable() {
@Override
public void run() {
method01();
}
},"A");
Thread t02B = new Thread(new Runnable() {
@Override
public void run() {
method02();
}
},"B");
Thread t02C = new Thread(new Runnable() {
@Override
public void run() {
method3();
}
},"C");
t02A.start();
t02B.start();
t02C.start();//-------------
public void method01(){
synchronized (this) {
int i=0;
while(i++ < 3){
System.out.println(Thread.currentThread().getName() +":"+ i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void method02(){
//第2种方式:当一个线程访问object的一个synchronized(this)同步代码块时,
//其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
synchronized (this) {
int j=0;
while(j++ < 3){
System.out.println(Thread.currentThread().getName() +":"+ j);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/*
* 当一个线程访问object的一个synchronized(this)同步代码块时,
* 它就获得了这个object的对象锁。
* 结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
*/
public synchronized void method3(){
int k=0;
while(k++ < 3){
System.out.println(Thread.currentThread().getName() +":"+ k);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}执行结果:
synchronized 关键字使用
--------------------------
B:1
B:2
B:3
C:1
C:2
C:3
A:1
A:2
A:3
第三个例子
final InnerObject innerObj = new InnerObject();// 对象锁
System.out.println("synchronized 关键字使用 \n" +"--------------------------");
Thread t03A = new Thread(new Runnable() {
@Override
public void run() {
outerMethod01(innerObj);
}
},"A");
Thread t03B = new Thread(new Runnable() {
@Override
public void run() {
outerMethod02(innerObj);
}
},"B");
t03A.start();
t03B.start();
class InnerObject{
private void innerMethod01(){
int i=0;
while(i++ < 3){
System.out.println(Thread.currentThread().getName() +":"+ i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void innerMethod02(){
int j=0;
while(j++ < 3){
System.out.println(Thread.currentThread().getName() +":"+ j);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 外部类方法1
*/
private void outerMethod01(InnerObject innerObj){
synchronized (innerObj) {
innerObj.innerMethod01();
}
}
/**
* 外部类方法2
*/
private void outerMethod02(InnerObject innerObj){
innerObj.innerMethod02();
}
执行结果:
synchronized 关键字使用
--------------------------
A:1
B:1
B:2
A:2
B:3
A:3