线程并发-synchronized和Lock简单认知

前几天刚加深了线程的了解,期间在验证各种方法及多线程时遇到一些疑问,在高并发的情况下,怎么做才能保证程序还能按照我们预期的正常运行下去,这就是我们接下来探究下关于并发中的常用的一些线程安全方法、类等,仅个人见解, 忘广大学友纠正。

synchronized同步锁

  1. 特性

    1.1 类、方法和代码块正确的使用synchronized可以保证并发情况下互斥线程的代码同步(原子性);

    1.2 保证共享的资源可见性(类似volaite),每个线程都有自己的缓存区域,如果被锁的资源发生了变化,每个线程会弃从线程缓存中获取而去系统主内存中重新获取最新的(可见性

    1.3 在并发情况下,可以保障线程的有序执行 (有序

  2. 原理

    同步锁可以针对类、代码块和对象进行加锁,每个被修饰的对象,在线程调用获取时都会经过监视器monitor进行操作;

    当线程调用对象时,如果该对象的监视器中进入的线程数为0时,则当前线程为对象锁的拥有者,数值+1,其他的线程调用时则会阻塞进行等待;

    如果当前线程再次获取该对象时,监视器进入的线程数值再+1;

    在线程执行完成释放资源后,监视器中进入的线程数为0时,阻塞的线程按序获取对象。

    当我们在对对象或者类(代码块)加锁时:

    public class Test1 {
    
    	private static Boolean flag = true;
    
    	public void add() {
    synchronized(flag) {
    if (flag) {
    flag = false;
    }
    }
    } public static void main(String args[]) {
    Test1 t1 = new Test1();
    t1.add();
    System.out.println(flag);
    }
    }
    // 查看编译字节文件
    public Test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
    stack=1, locals=1, args_size=1
    0: aload_0
    1: invokespecial #1 // Method java/lang/Object."<init>":()V
    4: return
    LineNumberTable:
    line 1: 0 public void add();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
    stack=2, locals=3, args_size=1
    0: getstatic #2 // Field flag:Ljava/lang/Boolean;
    3: dup
    4: astore_1
    5: monitorenter
    6: getstatic #2 // Field flag:Ljava/lang/Boolean;
    9: invokevirtual #3 // Method java/lang/Boolean.booleanValue:()Z
    12: ifeq 22
    15: iconst_0
    16: invokestatic #4 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
    19: putstatic #2 // Field flag:Ljava/lang/Boolean;
    22: aload_1
    23: monitorexit
    24: goto 32
    27: astore_2
    28: aload_1
    29: monitorexit
    30: aload_2
    31: athrow
    32: return
    Exception table:
    from to target type
    6 24 27 any
    27 30 27 any

    通过查看字节码(使用javap -v/verbose命令查看编码文件)来看,jvm通过monitorenter和monitorexit进入和退出监视器,为了确保释放对象锁,存在多次monitorexit;

    当我们在方法体上加锁时:

    public class Test {
    
    	private int num;
    
    	public synchronized int add() {
    return num ++;
    } public static void main(String[] args) {
    Test t = new Test();
    System.out.println(t.add());
    }
    }
    // 字节码
    public Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
    stack=1, locals=1, args_size=1
    0: aload_0
    1: invokespecial #1 // Method java/lang/Object."<init>":()V
    4: return
    LineNumberTable:
    line 1: 0 public synchronized int add();
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
    stack=4, locals=1, args_size=1
    0: aload_0
    1: dup
    2: getfield #2 // Field num:I
    5: dup_x1
    6: iconst_1
    7: iadd
    8: putfield #2 // Field num:I
    11: ireturn
    LineNumberTable:
    line 6: 0

    出现了ACC_SYNCHRONIZED变量,与在代码块加锁不同的是,方法体加锁是根据ACC_SYNCHRONIZED标识的true/false来判断是否同步,而代码块同步锁则是通过monitorenter和monitorexit指令进行同步操作

  3. 应用场景

    在多线程中,我们要实现资源共享时可以通过加锁来实现;同步代码块逻辑过于复杂不推荐使用

Lock

  1. 特性

    • Lock需要手动加锁、手动解锁 (lock(); unlock();)

    • tryLock非阻塞方式获取锁,判断是否已经被占有锁,有则返回false,true则占有锁;同样可以设置时间,在时间之内尝试获取锁;

      lock.tryLock(6000, TimeUnit.MILLISECONDS) // 线程AB先后获取锁,A占有锁B会在后面的6秒尝试再次获取获取不到直接进入false逻辑。
    • lock.lockInterruptibly(), 等待获取锁的线程可以中断 thread.interrupt(); 声明抛出InterruptedException异常

    • Lock释放锁如有异常捕获需在finally中释放锁

  2. 原理

    Lock常用的实现类ReentrantLock、ReadWriteLock等,其基本都是依赖AQS(AbstractQueuedSynchronizer)提供的加锁解锁方法。

总结

  1. synchronized和lock的区别

    • synchronized jvm在执行了monitorexit命令后会自动释放锁,lock需要手动释放锁,否则容易造成线程死锁
    • Lock是一个接口,synchronized是关键字
    • Lock可以判断线程是否拥有了锁、可以设置获取锁的时间
    • Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
  2. synchronized存在于多线程中,只读数据不涉及线程安全

  3. synchronized关键字会让没有得到锁的线程处于阻塞状态,在获得锁后变成可运行状态,这种变化涉及到系统用户模式和内核模式的转换,性能消耗大,代价高

并发-synchronized的更多相关文章

  1. java 并发——synchronized

    java 并发--synchronized 介绍 在平常我们开发的过程中可能会遇到线程安全性的问题,为了保证线程之间操作数据的正确性,我们第一想到的可能就是使用 synchronized 并且 syn ...

  2. 多线程并发 synchronized对象锁的控制与优化

    本文针对用户取款时多线程并发情境,进行相关多线程控制与优化的描述. 首先建立用户类UserTest.业务操作类SynchronizedTest.数据存取类DataStore,多线程测试类MultiTh ...

  3. Java并发——synchronized关键字

    前言: 只要涉及到Java并发那么我们就会考虑线程安全,实际上能够实现线程安全的方法很多,今天先介绍一下synchronized关键字,主要从使用,原理介绍 一.synchronized的使用方法 1 ...

  4. java 多线程并发 synchronized 同步机制及方式

    2. 锁机制 3. 并发 Excutor框架 4. 并发性与多线程介绍 1. synchronized  参考1. synchronized 分两种方式进行线程的同步:同步块.同步方法 1. 方法同步 ...

  5. Java并发--synchronized

    以下是本文的目录大纲: 一.什么时候会出现线程安全问题? 二.如何解决线程安全问题? 三.synchronized同步方法或者同步块 转载原文链接:http://www.cnblogs.com/dol ...

  6. Java并发——synchronized和ReentrantLock的联系与区别

    0 前言 本文通过使用synchronized以及Lock分别完成"生产消费场景",再引出两种锁机制的关系和区别,以及一些关于锁的知识点. 本文原创,转载请注明出处:http:// ...

  7. Java并发synchronized详解

    今天和大家一起学习下并发编程,先举一个简单的生活例子,我们去医院或者银行排队叫号,那每个工作人员之间如何保证不会叫重号呢? public class TicketDemo extends Thread ...

  8. Java精通并发-synchronized关键字原理详解

    关于synchronized关键字原理其实在当时JVM的学习[https://www.cnblogs.com/webor2006/p/9595300.html]中已经剖析过了,这里从研究并发专题的角度 ...

  9. 精通java并发-synchronized关键字和锁

    目前CSDN,博客园,简书同步发表中,更多精彩欢迎访问我的gitee pages synchronized关键字和锁 示例代码 public class MyThreadTest2 { public ...

随机推荐

  1. P2303 [SDOI2012]Longge的问题 我傻QwQ

    莫比乌斯反演学傻了$QwQ$ 思路:推式子? 提交:2次 错因:又双叒叕没开$long\space long$ 题解: $\sum_{i=1}^n gcd(i,n)$ $=\sum_{d|n}d\su ...

  2. scrollTop([val])

    scrollTop([val]) 概述 获取匹配元素相对滚动条顶部的偏移.广州大理石机械构件 此方法对可见和隐藏元素均有效. 参数 valString, NumberV1.2.6 设定垂直滚动条值 示 ...

  3. struts2 404错误

    action类必须放在xxxx.xxx.xxx.xxx.action  包下才可以.

  4. Python相关分析—一个金融场景的案例实操

    哲学告诉我们:世界是一个普遍联系的有机整体,现象之间客观上存在着某种有机联系,一种现象的发展变化,必然受与之关联的其他现象发展变化的制约与影响,在统计学中,这种依存关系可以分为相关关系和回归函数关系两 ...

  5. MySQL树

    树 树状图是一种数据结构,它是由n(n>=1)个有限结点组成一个具有层次关系的集合.把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的. 它具有以下的特点:每个结点有零个 ...

  6. RSA加密算法c++简单实现

    RSA是一种非对称加密算法,在公开密钥和电子商业中RSA被广泛使用.它是基于一个很简单的数论事实,两个素数相乘很容易,对两素数乘积因式分解很困难.原理就不再阐述了,我谈谈算法的编程实现过程. 一.RS ...

  7. mysql中的utf8mb4、utf8mb4_unicode_ci、utf8mb4_general_ci的关系

    mysql中的utf8mb4.utf8mb4_unicode_ci.utf8mb4_general_ci的关系 一.总结 一句话总结: utf8mb4是utf8的超集并完全兼容utf8,能够用四个字节 ...

  8. 【转】Qt编写串口通信程序全程图文讲解

    本文章原创于www.yafeilinux.com 转载请注明出处. (说明:我们的编程环境是windows xp下,在Qt Creator中进行,如果在Linux下或直接用源码编写,程序稍有不同,请自 ...

  9. Python 生成随机数函数和加密函数(MD5)

    内容来自debugtalk import hashlib import random import string def gen_random_string(str_len): '''生成指定长度的随 ...

  10. Oracle 报错 ORA-03290的处置

    MySql 的tuancate命令是直接truncate tableName,但在Oracle需要写成truncate table tableName,改正就好了. --END-- 2019.10.1 ...