java 对象锁学习

摘要:
Java将对象锁与每个对象相关联。通常,锁分为对象锁和类锁。它们的本质是对象锁,但对象锁与类对象相关联,而类锁与类类对象java.lang.class相关联。“);23}24}25}26}类锁作用于类的类对象。对于一个类,无论该类有多少实例,它的静态变量和静态方法都只有一个副本,存储在类对象中。”);24}25}26}27}对象锁将锁定类的实例对象,每个新操作将获得一个新的实例对象。对于同步修改的非静态方法或将参数作为实例对象传递的语句块,每个实例对象都有自己的锁。

机制

  锁机制是用来解决多线程共享资源时产生的冲突问题的。java 为每一个对象关联一个对象锁,通常把锁分为对象锁和类锁,他们的本质都是对象锁,只不过对象锁关联的是类的 Object 对象 (java.lang.Object),而类锁关联的是类的 Class 对象 java.lang.Class。
  jvm 对每个锁都有一个计数

  • 若该计数为 0,则锁没有被占用,可以被访问它的线程来持有
  • 一个对象的对象锁已被某个线程持有,新的线程来访问时将被挂起,知道持有它的线程释放该锁并且计数为 0
  • 一个线程已经持有了某个对象的锁,该线程再次访问该对象锁时可以重入,且计数 +1
  • 一个线程释放对象锁时,该锁的计数 -1,当某个锁的计数为 0 时锁被释放,可以被线程竞争

分类

  • 不管怎么分类,java 中通过 synchronized 来实现的锁其本质都是对象锁
  • java 内部同步机制实现通常有两种方式,synchronized 修饰方法和语句块
  • synchronized 关键字作用于对象,这个对象可以是类的实例对象,也可以是 Class 对象

    • 类锁

  1 public class SyncObject {
  2     // 类锁1:通过static方法加同步锁
  3     public static synchronized void syncMethod1() {
  4         try {
  5             System.out.println("testMethod1 start!");
  6             Thread.sleep(3000);
  7         } catch (InterruptedException e) {
  8             e.printStackTrace();
  9         }
 10         System.out.println("testMethod1 end!");
 11     }
 12 
 13     public void syncMethod2() {
 14         // 类锁2:通过同步语句块传递Class类型参数
 15         synchronized (SyncObject.class) {
 16             try {
 17                 System.out.println("testMethod2 start!");
 18                 Thread.sleep(3000);
 19             } catch (InterruptedException e) {
 20                 e.printStackTrace();
 21             } finally {
 22                 System.out.println("testMethod2 end!");
 23             }
 24         }
 25     }
 26 }

类锁作用于类的 Class 对象,对一个类来说,无论该类有多少个实例,它的静态变量和静态方法都只有一份,保存在 Class 对象中。通过对 Class 对象加锁来实现的同步语句或同步方法,无论该对象的哪个实例来访问,都需要竞争这个类锁

  •    对象锁

  1 public class SyncObject {
  2     // 对象锁1(方法锁):通过方法加同步锁
  3     public synchronized void syncMethod1() {
  4         try {
  5             System.out.println("testMethod1 start!");
  6             Thread.sleep(3000);
  7         } catch (InterruptedException e) {
  8             e.printStackTrace();
  9         }
 10         System.out.println("testMethod1 end!");
 11     }
 12 
 13     public void syncMethod2() {
 14         // 对象锁2:通过同步语句块传递Object类型参数
 15         synchronized (this) {
 16         // 此处的参数可以是本实例this,也可以是其它实例比如new SyncObject(),传入哪个实例就对哪个实例加锁
 17             try {
 18                 System.out.println("testMethod2 start!");
 19                 Thread.sleep(3000);
 20             } catch (InterruptedException e) {
 21                 e.printStackTrace();
 22             } finally {
 23                 System.out.println("testMethod2 end!");
 24             }
 25         }
 26     }
 27 }


对象锁会对类的实例对象加锁,每一个 new 操作都会获得一个新的实例对象,对于 synchronized 修饰的非 static 方法或传递参数为实例对象的语句块,各个实例对象会拥有自己的锁。

TIPS

    • synchronized 的作用范围是对象

      • synchronized 修饰的代码块需要传入一个对象参数(这个对象可以使 Class 对象),这个对象参数就是它的作用范围
      • synchronized 修饰的非静态方法的作用范围是 this,即当前对象实例。修饰静态方法时作用范围是这个类,即 Class 对象
    • synchronized 的粒度针不可再分


      因为锁是针对整个对象的,所以当某个对象的锁被持有后,其它线程不能持有该锁
      • 当一个线程调用某个对象 a 的 synchronized 方法(a.syncMethod1)在该方法结束之前,该对象的其它 synchronized 方法 (a.syncMethod2..) 都将不能被调用。同步代码块 synchronized(a)与 a.syncMethod1 有同样的作用周期
      • 当一个线程调用某个类 A 的 static synchronized 方法(A.staticSyncMethod1)在该方法结束前,该类的其它 static synchronized 方法(A.staticSyncMethod2..)都将不能被调用
      • 当一个线程调用某个对象 a 的 synchronized 方法(a.syncMethod1)在该方法结束之前,该类的其它 static synchronized 方法 (A.syncMethod2..) 还可以被调用,反之也成立
      • synchronized 的只对它修饰的模块加锁

        • 未被 synchronized 修饰的模块是可以被异步访问的, 因为线程访问它的时候并不需要获取对象锁

      免责声明:文章转载自《java 对象锁学习》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

      上篇WinForm界面布局空间WeifenLuo.WinformUI.DockingEclipse java文件、包、工程左下角有感叹号原因及处理方法下篇

      宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

      相关文章

      Redis分布式锁,看完不懂你打我

      简易的redis分布式锁 加锁: set key my_random_value NX PX 30000 这个命令比setnx好,因为可以同时设置过期时间。不设置过期时间,应用挂了,解不了锁,就一直锁住了。 解锁: if redis.call("get",KEYS[1])==ARGV[1] then return redis.call("del",K...

      CyclicBarrier:人齐了,老司机就可以发车了!

      上一篇咱讲了 CountDownLatch 可以解决多个线程同步的问题,相比于 join 来说它的应用范围更广,不仅可以应用在线程上,还可以应用在线程池上。然而 CountDownLatch 却是一次性的计数器,以王者农药来说,咱们不可能一场团战就决定比赛的输赢,所以在某些场景下,咱们是需要重复使用某个等待功能的,这就是我们今天要介绍的另一个主角——Cyc...

      多线程知识点总结(一)

      第一章  Java多线程技能   1、实现多线程的方式:一种是继承Thread类,另外一种是实现Runnable接口。       这两者的区别是:继承Thread类的本质是多个线程分别完成自己的任务,实现Runnable接口的本质是多个线程共同完成一个任务。 举例如下: 继承Thread类的,我们相当于拿出三件事即三个卖票10张的任务分别分给三个窗口,他...

      Android Handler消息传递

      一、背景 出于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,可能导致线程安全问题。为了解决这个问题,Android制定了一条简单的原则:只允许UI线程(亦即主线程)修改Activity中的UI组件。 当一个程序第一次启动时,Android会同时启动一条主线程,主线程主要负责处理与UI相关的事件,如用户的按键...

      sqlalchemy 数据库操作

      1、简介 一种ORM 2、安装 pip3 install -i https://pypi.douban.com/simple sqlalchemy 3、连接数据库 from sqlalchemy importcreate_engine engine =create_engine( "mysql+pymysql://root:密码@1...

      sqlite报SQLITE_LOCKED "Database table is locked"

      今天调了一天程序,最后远程的ORACLE都好,做下压力测试.惊奇的发现SQLITE报错.. 说什么数据表锁了..... 结果调到了现在...很是郁闷. 情况如下: 每个线程打开自己的SQLITE连接.线程间不混用. 1 if (sqlite3_open_v2(strdb, \ 2 db, \ 3...