JAVA synchronized关键字锁机制(中)

Posted 沁园下的一缕残云

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA synchronized关键字锁机制(中)相关的知识,希望对你有一定的参考价值。

synchronized 锁机制简单的用法,高效的执行效率使成为解决线程安全的首选。 下面总结其特性以及使用技巧,加深对其理解。

特性:

  1. Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

      2. 当一个线程同时访问object的一个synchronized(this)同步代码块时,其它线程仍然可以访问非修饰的方法或代码块。

      3. 当多个线程同时访问object的synchronized(this)同步代码块时,会存在互斥访问,其它线程会阻塞直到获取锁。

      4. 当线程访问object的synchronized(this)同步代码块时,同一个线程可以多次获取锁,当然也不需要释放多次。获取和释放必须相同。

      5. 所有的对象都可以获取锁,也可以释放锁。

      6. 所有的类也可以获取锁和释放锁,因此静态方法也可以加锁。而特性同上。

猜想:

     在jvm中对每个对象都有一个记录锁的状态,当同一个线程访问锁时候就会累加,其它线程访问要等到状态变为未锁状态,当让相同线程释放锁会累减。

 质疑:

    那么对于类锁来说,应该是所有对象都可以获取锁,那么锁是全局的对所有对象都有效?

public class SynchronizedMtdTest {

  public static void main(String[] args) {

    new Thread(new Runnable() {
      @Override
      public void run() {
        SynchronizedMtdTest.appendStr();
      }
    }).start();
    new Thread(new Runnable() {
      @Override
      public void run() {
        SynchronizedMtdTest.printStr();
      }
    }).start();
    new Thread(new Runnable() {
      @Override
      public void run() {
        SynchronizedMtdTest synchronizedMtdTest = new SynchronizedMtdTest();
        synchronizedMtdTest.appendStr();
      }
    }).start();
    new Thread(new Runnable() {
      @Override
      public void run() {
        SynchronizedMtdTest synchronizedMtdTest = new SynchronizedMtdTest();
        synchronizedMtdTest.printStr();
      }
    }).start();
    new Thread(new Runnable() {
      @Override
      public void run() {
        SynchronizedMtdTest synchronizedMtdTest = new SynchronizedMtdTest();
        synchronizedMtdTest.append();
      }
    }).start();
  }

  public synchronized static void appendStr() {
    System.out.println("pid=" + Thread.currentThread().getId() + "------appendStr------");
    try {
      Thread.sleep(1000);
      System.out.println("pid=" + Thread.currentThread().getId() + "------appendStr1000------");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

  }

  public static void append() {
    System.out.println("pid=" + Thread.currentThread().getId() + "------append------");
    try {
      Thread.sleep(3000);
      System.out.println("pid=" + Thread.currentThread().getId() + "------append3000------");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

  }

  public synchronized static void printStr() {
    System.out.println("pid=" + Thread.currentThread().getId() + "------printStr------");
    try {
      Thread.sleep(6000);
      System.out.println("pid=" + Thread.currentThread().getId() + "------printStr6000------");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

}

结果:

pid=10------appendStr------
pid=14------append------
pid=10------appendStr1000------
pid=13------printStr------
pid=14------append3000------
pid=13------printStr6000------
pid=12------appendStr------
pid=12------appendStr1000------
pid=11------printStr------
pid=11------printStr6000------

 分析结果可以看出对于静态方法加锁,所有的线程调用方法,不管怎样都会互斥,而为加锁不会互斥。

因此:

    对于类锁来说应该在持久代也就是方法区有对具体类也有加锁机制,而且原理同对象锁。

那么:

    可见,上面可以做如下修改达到相同效果。

public static void appendStr() {
    synchronized (SynchronizedMtdTest.class) {
      System.out.println("pid=" + Thread.currentThread().getId() + "------appendStr------");
      try {
        Thread.sleep(1000);
        System.out.println("pid=" + Thread.currentThread().getId() + "------appendStr1000------");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  public static void printStr() {
    synchronized (SynchronizedMtdTest.class) {
      System.out.println("pid=" + Thread.currentThread().getId() + "------printStr------");
      try {
        Thread.sleep(6000);
        System.out.println("pid=" + Thread.currentThread().getId() + "------printStr6000------");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

 结果:

pid=10------appendStr------
pid=10------appendStr1000------
pid=13------printStr------
pid=13------printStr6000------
pid=12------appendStr------
pid=12------appendStr1000------
pid=11------printStr------
pid=11------printStr6000------

 

以上是关于JAVA synchronized关键字锁机制(中)的主要内容,如果未能解决你的问题,请参考以下文章

深入显出一篇能懂Java锁机制,Synchronized和ReentrantLock

Java锁机制总结

Java锁synchronized关键字学习系列之批量重偏向和批量撤销

java多线程——锁机制synchronized(同步方法)

java 多线程9 : synchronized锁机制 之 代码块锁

synchronized学习