JUC之Lock接口以及Synchronized回顾

JUC之Lock接口以及Synchronized回顾

Lock接口

Synchronized关键字回顾:

线程编程步骤(上):

  1. 创建资源类,在资源类创建属性操作方法
  2. 创建多个线程,调用资源类的操作方法

创建线程的四种方式:

  1. 继承Thread
  2. 实现Runnable接口
  3. 使用Callable接口
  4. 使用线程池

使用synchronized同步实现售票问题:

只有当资源是空闲的时候,线程才能访问。

 /**  * 创建资源  */ class ticket{     private  int number = 30;     public synchronized void sell(){         if(number >0){             System.out.println(Thread.currentThread().getName()+":卖出"+number--+"剩余:"+number);         } ​     } } ​ /**  * 创建多个线程,调用资源类的操作方法  */ public class sellTicket {     public static void main(String[] args) {         /**          * 创建资源          */         ticket ticket = new ticket();         /**          * 创建三个线程(售票员)          */         new Thread(new Runnable() {             public void run() {                 for (int i = 0; i < 40; i++) {                     ticket.sell();                 }             }         }, "aaa").start();         new Thread(new Runnable() {             public void run() {                 for (int i = 0; i < 40; i++) {                     ticket.sell();                 }             }         }, "bbb").start();         new Thread(new Runnable() {             public void run() {                 for (int i = 0; i < 40; i++) {                     ticket.sell();                 }             }         }, "ccc").start();     } } ​

学习《Java并发编程的艺术》一节是synchronized的实现原理与应用:

Java中的每一个对象都可以作为锁:

  1. 对于同步方法,锁的是当前的对象。
  2. 对于静态方法,锁的是当前类的class对象。
  3. 对于静态代码块,Synchonized括号里配置的对象。

当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。

那么锁到底存在哪里呢?锁里面会存储什么信息呢?

这个问题是该书中的一个问题,对个人来说有点抽象,主要点是:JVM基于进入和退出Monitor(监视器)对象来实现方法同步和代码块同步,但两者的实现细节不一样。

代码块同步是使用monitorenter 和monitorexit指令实现的,而方法同步是使用另外一种方式实现的,细节在JVM规范里并没有 详细说明。但是,方法的同步同样可以使用这两个指令来实现。

monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结 束处和异常处,JVM要保证每个monitorenter必须有对应的monitorexit与之配对。任何对象都有 一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter 指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁。

其中monitorenter主要是获取监视器锁,monitorexit主要是释放监视器锁。

synchonized中的一个概念是Java对象头:

synchronized用的锁是存放在Java对象头里面的。

非数组类型数组类型虚拟机3个字宽2个字宽

需要注意的是:在32位虚拟机中:1字宽=4字节,即:32bit

Java对象头里的Mark Word里面默认存储对象HashCode、分代年龄和锁标记位。

运行期间,Mark Word里面存储的数据会随着锁标志位的变化而变化。

32位JVM的Mark Word的默认存储结构与在64位JVM不相同

Lock接口并创建实例:

Java并发编程的艺术

在JavaSE5之前使用的是synchronized关键字实现锁功能,5v之后并发包中新增Lock接口以及相关实现类用来实现锁功能,提供与synchronized类似的同步关系,但是比其更具有灵活性和扩展性(拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁)。

查看Lock的文档得知:

使用 lock 块来调用 try,在之前/之后的构造中,最典型的代码如下:

  class X {    private final ReentrantLock lock = new ReentrantLock();    // ...public void m() {       lock.lock();  // block until condition holds      try {        // ... method body      } finally {        lock.unlock()      }    }  }  

根据上述的代码,实现买票代码:

 import java.util.concurrent.locks.ReentrantLock; class ticket2{     private int number = 30; ​     //创建一个重入锁     private ReentrantLock lock = new ReentrantLock(); ​     public void sale(){         //在内容之前加锁         lock.lock();         if(number >0){             System.out.println(Thread.currentThread().getName()+":卖出"+number--+"剩余:"+number);         }         //在内容之后解锁         lock.unlock();     } } ​ public class lockCase {     public static void main(String[] args) {         ticket2 tk = new ticket2();         //创建线程         new Thread(()->{             for (int i = 0; i < 40; i++) {                 tk.sale();             }         },"aaa").start();         new Thread(()->{             for (int i = 0; i < 40; i++) {                 tk.sale();             }         },"bbb").start();         new Thread(()->{             for (int i = 0; i < 40; i++) {                 tk.sale();             }         },"bbb").start();     } }

上述代码中,在ticket2类中存在一个问题就是,当lock中间内容如果出现报错,那么后面的代码无法执行,也就是锁无法释放。所以我们需要将unlock()放到finally中。

目的是保证在获取到锁之后,最终能够被释放。

 public void sale(){         //在内容之前加锁         lock.lock();         try{             if(number >0){                 System.out.println(Thread.currentThread().getName()+":卖出"+number--+"剩余:"+number);             }             //在内容之后解锁         }finally{             lock.unlock();         } ​     }

__EOF__

  • 本文作者: xbhog
  • 本文链接: https://www.cnblogs.com/xbhog/p/15703110.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
    相关文章
    返回顶部