zoukankan      html  css  js  c++  java
  • synchronized锁和lock锁

    Java多线程加锁机制,有两种:

    • Synchronized
    • 显式Lock

    接下来就讲一下这两种加锁方式。

    一、synchronized

    1.1synchronized锁是什么?

    synchronized是Java的一个关键字,它能够将代码块(方法)锁起来

    • 它使用起来是非常简单的,只要在代码块(方法)添加关键字synchronized,即可以实现同步的功能

        public synchronized void test() {
            // doSomething
        }

    synchronized是一种互斥锁

    • 一次只能允许一个线程进入被锁住的代码块

    synchronized是一种内置锁/监视器锁

    • Java中每个对象都有一个内置锁(监视器,也可以理解成锁标记),而synchronized就是使用对象的内置锁(监视器)来将代码块(方法)锁定的! (锁的是对象,但我们同步的是方法/代码块)

    1.2synchronized用处是什么?

    • synchronized保证了线程的原子性(被保护的代码块是一次被执行的,没有任何线程会同时访问)
    • synchronized还保证了可见性(当执行完synchronized之后,修改后的变量对其他的线程是可见的)

    Java中的synchronized,通过使用内置锁,来实现对变量的同步操作,进而实现了对变量操作的原子性和其他线程对变量的可见性,从而确保了并发情况下的线程安全。

    1.3synchronized的原理

    同步代码块:

    • monitorenter和monitorexit指令实现的

    同步方法(在这看不出来需要看JVM底层实现)

    • 方法修饰符上的ACC_SYNCHRONIZED实现。

    synchronized底层是是通过monitor对象,对象有自己的对象头,存储了很多信息,其中一个信息标示是被哪个线程持有。

    1.4synchronized如何使用

    synchronized一般我们用来修饰三种东西:

    • 修饰普通方法
    • 修饰代码块
    • 修饰静态方法

    1.5重入锁

    我们来看下面的代码:

    public class Widget {
    // 锁住了
      public synchronized void doSomething() {
        ...
      }
    }
    
    public class LoggingWidget extends Widget {
    // 锁住了
      public synchronized void doSomething() {
        System.out.println(toString() + ": calling doSomething");
        super.doSomething();
      }
    }

    当线程A进入到LoggingWidget的doSomething()方法时,此时拿到了LoggingWidget实例对象的锁。

    随后在方法上又调用了父类Widget的doSomething()方法,它又是被synchronized修饰。

    那现在我们LoggingWidget实例对象的锁还没有释放,进入父类Widget的doSomething()方法还需要一把锁吗?

    不需要的!

    因为锁的持有者是“线程”,而不是“调用”。线程A已经是有了LoggingWidget实例对象的锁了,当再需要的时候可以继续“开锁”进去的!

    这就是内置锁的可重入性。记住,持有锁的是线程。

    1.6释放锁的时机

    当方法(代码块)执行完毕后会自动释放锁,不需要做任何的操作。

    当一个线程执行的代码出现异常时,其所持有的锁会自动释放。

    • 不会由于异常导致出现死锁现象

    二、Lock显式锁

    2.1Lock显式锁简单介绍

    Lock显式锁是JDK1.5之后才有的,之前我们都是使用Synchronized锁来使线程安全的~

    Lock显式锁是一个接口,我们来看看:

    • Lock方式来获取锁支持中断、超时不获取、是非阻塞的
    • 提高了语义化,哪里加锁,哪里解锁都得写出来
    • Lock显式锁可以给我们带来很好的灵活性,但同时我们必须手动释放锁
    • 支持Condition条件对象
    • 允许多个读线程同时访问共享资源

    2.2synchronized锁和Lock锁使用哪个

    前面说了,Lock显式锁给我们的程序带来了很多的灵活性,很多特性都是Synchronized锁没有的。那Synchronized锁有没有存在的必要??

    必须是有的!!Lock锁在刚出来的时候很多性能方面都比Synchronized锁要好,但是从JDK1.6开始Synchronized锁就做了各种的优化

    • 优化操作:适应自旋锁,锁消除,锁粗化,轻量级锁,偏向锁。

    所以,到现在Lock锁和Synchronized锁的性能其实差别不是很大!而Synchronized锁用起来又特别简单。Lock锁还得顾忌到它的特性,要手动释放锁才行(如果忘了释放,这就是一个隐患)

    所以说,我们绝大部分时候还是会使用Synchronized锁,用到了Lock锁提及的特性,带来的灵活性才会考虑使用Lock显式锁

    2.3公平锁

    公平锁理解起来非常简单:

    • 线程将按照它们发出请求的顺序来获取锁

    非公平锁就是:

    • 线程发出请求的时可以“插队”获取锁

    Lock和synchronize都是默认使用非公平锁的。如果不是必要的情况下,不要使用公平锁

    • 公平锁会来带一些性能的消耗的

    三、Java锁简单总结

    本文讲了synchronized内置锁和简单描述了一下Lock显式锁,总得来说:

    • synchronized好用,简单,性能不差
    • 没有使用到Lock显式锁的特性就不要使用Lock锁了。
  • 相关阅读:
    ADB常用命令
    HttpClient4.x 使用cookie保持会话
    HttpClient发起Http/Https请求工具类
    MakeFile 文件的使用
    SQL连接查询和嵌套查询详解
    Linux中进程控制块PCB-------task_struct结构体结构
    Mysql数据库--语句整理/提升/进阶/高级使用技巧
    进程池分析
    mmap和shm共享内存的区别和联系
    IO多路复用模型之epoll实现机制
  • 原文地址:https://www.cnblogs.com/harpoonJava/p/13213203.html
Copyright © 2011-2022 走看看