• 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------
  • 相关阅读:
    有关mysql数据库的编码
    成功启动了Apache却没有启动apache服务器
    遍历元素绑定事件时作用域是怎么回事啊,为什么要用this关键字,而直接使用元素本身就不行?
    js中给函数传参函数时,函数加括号与不加括号的区别
    win64安装及配置apache+php+mysql
    ubuntu 12.04 安装nginx
    ubuntu下怎么显示右上角的小键盘
    ubuntu12.04安装Vmware Tools
    PyCharm教程
    jira使用指南
  • 原文地址:https://www.cnblogs.com/maybo/p/7560754.html
Copyright © 2020-2023  润新知