深入理解Java中Synchronized(对象锁)和Static Synchronized(类锁)的区别

一、知识点回顾:
   1.、synchronized是Java中的关键字,是一种同步锁
   2、synchronized关键字可以用在方法和代码块上。这些方法或者代码块可以使静态的也可以是非静态的。
   3、在java中同步由synchronized关键字实现的,你可以在你类中的方法或者块上使用synchronized关键字,关键字不能在类定义的变量或者属性上使用。
对象级别的锁
public class DemoClass {
public synchronized void demoMethod(){}
}
public class DemoClass {
public void demoMethod(){
synchronized (this) {
//other thread safe code
}
}
}
public class DemoClass {
private final Object lock = new Object();
public void demoMethod(){
synchronized (lock){
//other thread safe code
}
}
}
类级别的锁
public class DemoClass {
public synchronized static void demoMethod(){}
}
public class DemoClass{
public void demoMethod(){
synchronized (DemoClass.class){
//other thread safe code
}
}
}
public class DemoClass {
private final static Object lock = new Object();
public void demoMethod(){
synchronized (lock){
//other thread safe code
}
}
}
二、一段代码枷锁后的执行步骤
   ①一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,
   ②在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁);
   ③如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中)。 
   ④取到锁后,他就开始执行同步代码(被synchronized修饰的代码); 
   ⑤线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。
   ⑥这样就保证了同步代码在统一时刻只有一个线程在执行。     

三、Synchronized和Static Synchronized区别
       synchronized是对类的当前实例(当前对象)进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”, 类的两个不同实例就没有这种约束了。
      static synchronized恰好就是要控制类的所有实例的并发访问,static synchronized是限制多线程中该类的所有实例同时访问jvm中该类所对应的代码块
      实际上,在类中如果某方法或某代码块中有 synchronized,那么在生成一个该类实例后,该实例也就有一个监视块,防止线程并发访问该实例的synchronized保护块,而static synchronized则是所有该类的所有实例公用得一个监视块
写个demo验证下
public class MyThread extends Thread {
private static volatile int n = 0;

public void run() {
for (int i = 0; i < 10; i++) {
add();
try {
sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


private static synchronized void add() {
n++;
}

public static void main(String[] args) throws InterruptedException {
Thread threads[] = new Thread[100];
for (int i = 0; i < threads.length; i++) {
threads[i] = new MyThread();
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join(); //等待该线程终止
}
System.out.println(" n= " + n);
}
}
运行结果   n= 1000
然后我们把add()方法前的static去掉试下,结果是994,运行结果是不确定的,但都小于1000

四、总结
     1、 除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/*区块*/}(或者synchronized(obj){/*区块*/}),它的作用域是当前对象; 被synchronized修饰符修饰的实例方法,跟整个方法体被一个synchronized(this) { ... } 包围住,虽然字节码看起来有差异,但语义完全一样。
      2、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;
     3、根据java语言的规定,你不能在构造方法上使用synchronized关键字,这是非法的并且会导致编译错误
     4、java中的同步方法会增加你程序的性能的消耗,所以只有在正真需要的时候才使用同步。同样,使用同步代码块的地方是你代码中关键的地方。

原文地址:https://www.cnblogs.com/ZenoLiang/p/14713160.html