并发-synchronized
线程并发-synchronized和Lock简单认知
前几天刚加深了线程的了解,期间在验证各种方法及多线程时遇到一些疑问,在高并发的情况下,怎么做才能保证程序还能按照我们预期的正常运行下去,这就是我们接下来探究下关于并发中的常用的一些线程安全方法、类等,仅个人见解, 忘广大学友纠正。
synchronized同步锁
特性
1.1 类、方法和代码块正确的使用synchronized可以保证并发情况下互斥线程的代码同步(原子性);
1.2 保证共享的资源可见性(类似volaite),每个线程都有自己的缓存区域,如果被锁的资源发生了变化,每个线程会弃从线程缓存中获取而去系统主内存中重新获取最新的(可见性)
1.3 在并发情况下,可以保障线程的有序执行 (有序)
原理
同步锁可以针对类、代码块和对象进行加锁,每个被修饰的对象,在线程调用获取时都会经过监视器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指令进行同步操作
应用场景
在多线程中,我们要实现资源共享时可以通过加锁来实现;同步代码块逻辑过于复杂不推荐使用
Lock
特性
Lock需要手动加锁、手动解锁 (lock(); unlock();)
tryLock非阻塞方式获取锁,判断是否已经被占有锁,有则返回false,true则占有锁;同样可以设置时间,在时间之内尝试获取锁;
lock.tryLock(6000, TimeUnit.MILLISECONDS) // 线程AB先后获取锁,A占有锁B会在后面的6秒尝试再次获取获取不到直接进入false逻辑。
lock.lockInterruptibly(), 等待获取锁的线程可以中断 thread.interrupt(); 声明抛出InterruptedException异常
Lock释放锁如有异常捕获需在finally中释放锁
原理
Lock常用的实现类ReentrantLock、ReadWriteLock等,其基本都是依赖AQS(AbstractQueuedSynchronizer)提供的加锁解锁方法。
总结
synchronized和lock的区别
- synchronized jvm在执行了monitorexit命令后会自动释放锁,lock需要手动释放锁,否则容易造成线程死锁
- Lock是一个接口,synchronized是关键字
- Lock可以判断线程是否拥有了锁、可以设置获取锁的时间
- Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
synchronized存在于多线程中,只读数据不涉及线程安全
synchronized关键字会让没有得到锁的线程处于阻塞状态,在获得锁后变成可运行状态,这种变化涉及到系统用户模式和内核模式的转换,性能消耗大,代价高
并发-synchronized的更多相关文章
- java 并发——synchronized
java 并发--synchronized 介绍 在平常我们开发的过程中可能会遇到线程安全性的问题,为了保证线程之间操作数据的正确性,我们第一想到的可能就是使用 synchronized 并且 syn ...
- 多线程并发 synchronized对象锁的控制与优化
本文针对用户取款时多线程并发情境,进行相关多线程控制与优化的描述. 首先建立用户类UserTest.业务操作类SynchronizedTest.数据存取类DataStore,多线程测试类MultiTh ...
- Java并发——synchronized关键字
前言: 只要涉及到Java并发那么我们就会考虑线程安全,实际上能够实现线程安全的方法很多,今天先介绍一下synchronized关键字,主要从使用,原理介绍 一.synchronized的使用方法 1 ...
- java 多线程并发 synchronized 同步机制及方式
2. 锁机制 3. 并发 Excutor框架 4. 并发性与多线程介绍 1. synchronized 参考1. synchronized 分两种方式进行线程的同步:同步块.同步方法 1. 方法同步 ...
- Java并发--synchronized
以下是本文的目录大纲: 一.什么时候会出现线程安全问题? 二.如何解决线程安全问题? 三.synchronized同步方法或者同步块 转载原文链接:http://www.cnblogs.com/dol ...
- Java并发——synchronized和ReentrantLock的联系与区别
0 前言 本文通过使用synchronized以及Lock分别完成"生产消费场景",再引出两种锁机制的关系和区别,以及一些关于锁的知识点. 本文原创,转载请注明出处:http:// ...
- Java并发synchronized详解
今天和大家一起学习下并发编程,先举一个简单的生活例子,我们去医院或者银行排队叫号,那每个工作人员之间如何保证不会叫重号呢? public class TicketDemo extends Thread ...
- Java精通并发-synchronized关键字原理详解
关于synchronized关键字原理其实在当时JVM的学习[https://www.cnblogs.com/webor2006/p/9595300.html]中已经剖析过了,这里从研究并发专题的角度 ...
- 精通java并发-synchronized关键字和锁
目前CSDN,博客园,简书同步发表中,更多精彩欢迎访问我的gitee pages synchronized关键字和锁 示例代码 public class MyThreadTest2 { public ...
随机推荐
- on(events,[selector],[data],fn) 在选择元素上绑定一个或多个事件的事件处理函数
on(events,[selector],[data],fn) 概述 在选择元素上绑定一个或多个事件的事件处理函数.大理石平台精度等级 on()方法绑定事件处理程序到当前选定的jQuery对象中的元素 ...
- 查看PublicKeyToken和生成PublicKeyToken
http://hi.baidu.com/honfei/item/7777500b20d8ff8a02ce1bd2
- CF883H
CF883H 题意: 给你一个字符串,需要把它以最小的划分次数划分为x个长度相等的回文串,可以重新排列. 解法: 大模拟一个. 分别统计出现一次的字符和出现两次的字符,如果没有出现一次的字符,那么所有 ...
- 必懂知识——HashMap的实现原理
HashMap的底层数据结构 1.7之前是:数组+链表 数组的元素是Map.Entiry对象 当出现哈希碰撞的时候,使用链表解决, 先计算出key对应的数组的下标,这个数组的这个位置上为空,直接放入, ...
- Docker小记
1.Docker的安装 这里给一个比较通用的教程 Ubuntu 14.04 16.04 (使用apt-get进行安装) # step : 安装必要的一些系统工具 sudo apt-get update ...
- SpringCloud(四)之Netflix开源组件断路器Hystrix介绍
一.前言? 1.Netflix Hystrix断路器是什么? Netflix Hystrix是SOA/微服务架构中提供服务隔离.熔断.降级机制的工具/框架.Netflix Hystrix是断路器的一种 ...
- js对象和jQuery对象的区别
(1)js对象的三种基本定位方式 (A)通过ID属性:document.getElementById() (B)通过NAME属性:document.getElementsByName() (C)通过标 ...
- generator自动生成数据表
1.先写好自己要创建的字段等: 然后将将上面的在plsql中运行,创建数据表.
- C++ STL内存池
内存池出现原因:内存碎片 首先我们需要明确, 内存池的目的到底是什么? 首先你要知道的是, 我们每次使用new T来初始化类型T的时候, 其实发生了两步操作, 一个叫内存分配, 这一步使用的其实不是 ...
- jsp+UEditor粘贴word
最近公司做项目需要实现一个功能,在网页富文本编辑器中实现粘贴Word图文的功能. 我们在网站中使用的Web编辑器比较多,都是根据用户需求来选择的.目前还没有固定哪一个编辑器 有时候用的是UEditor ...