Synchronized方法锁、对象锁、类锁区别

synchronized关键字,我们一般称之为”同步锁“,用它来修饰需要同步的方法和需要同步代码块,默认是当前对象作为锁的对象。在修饰类时(或者修饰静态方法),默认是当前类的Class对象作为所的对象故存在着方法锁、对象锁、类锁 这样的概念

一.Synchronized方法锁(也叫对象锁)

1.修饰在方法上,多个线程调用同一个对象的同步方法会阻塞,调用不同对象的同步方法不会阻塞。(java对象的内存地址是否相同)

 public synchronized void obj3() {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
   }  

2.修饰代码块,这个this就是指当前对象(类的实例),多个线程调用同一个对象的同步方法会阻塞,调用不同对象的同步方法不会阻塞。(java对象的内存地址是否相同)

public void obj2() {
       synchronized (this) {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
       }
   }

3.修饰代码块,这个str就是指String对象,多个线程调用同一个对象的同步方法会阻塞,调用不同对象的同步方法不会阻塞。(java对象的内存地址是否相同)

 public void obj2() {
       String str=new String("lock");//在方法体内,调用一次就实例化一次,多线程访问不会阻塞,因为不是同一个对象,锁是不同的
       synchronized (str) {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
       }
   }  

public static void main(String[] args) throws InterruptedException {
test test=new test();
new Thread(new Runnable() {
@Override
public void run() {
test.obj2();
}
}).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            test.obj2();
        }
    }).start();
}  

//两个方法之间交替执行 没有阻塞
Thread-0 : 4
Thread-1 : 4
Thread-1 : 3
Thread-0 : 3
Thread-1 : 2
Thread-0 : 2
Thread-1 : 1
Thread-0 : 1
Thread-0 : 0
Thread-1 : 0

共用一个对象,多线程调用obj2同步方法,因为使用的是一个对象锁,会阻塞。

String str=new String("lock"); //对象放在方法外,调用方法的时候不会新创建一个对象。
   public void obj2() {
       synchronized (str) {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
       }
   }  
  Thread-0 : 4  
  Thread-0 : 3  
  Thread-0 : 2  
  Thread-0 : 1  
  Thread-0 : 0  
  Thread-1 : 4  
  Thread-1 : 3  
  Thread-1 : 2  
  Thread-1 : 1  
  Thread-1 : 0  

二.Synchronized类锁

1.Synchronized修饰静态的方法

  public static synchronized void obj3() {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
   }

2.synchronized (test.class) ,锁的对象是test.class,即test类的锁。

  public void obj1() {
        synchronized (test.class) {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
       }
   }

看完上面的例子,应该可以分清楚什么是对象锁和类锁了。

那么问题来了:在一个类中有两方法,分别用synchronized 修饰的静态方法(类锁)和非静态方法(对象锁)。多线程访问两个方法的时候,线程会不会阻塞?

 public static synchronized void obj3() {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
   }

 public synchronized void obj4() {
       int i = 5;
       while (i-- > 0) {
           System.out.println(Thread.currentThread().getName() + " : " + i);
           try {
               Thread.sleep(500);
           } catch (InterruptedException ie) {
           }
       }

}

答案是???

Thread-0 : 4
Thread-1 : 4
Thread-0 : 3
Thread-1 : 3
Thread-1 : 2
Thread-0 : 2
Thread-1 : 1
Thread-0 : 1
Thread-1 : 0
Thread-0 : 0

不会阻塞。

总结

到这么我们应该知道了:

1,要满足方法同步(或者代码块同步)就必须保证多线程访问的是同一个对象(在java内存中的地址是否相同)。

2,类锁和对象锁同时存在时,多线程访问时不会阻塞,因为他们不是一个锁。

感谢原作者:Synchronized方法锁、对象锁、类锁区别 - 不懂就查 - 博客园

你可能感兴趣的:(多线程)