摘要:只有首先获得锁的任务线程才能继续获取该对象上的多个锁。会进一步对时失败的那些线程进行阻塞操作调用操作系统的信号量此段来摘自别处。提供了多样化的同步,比如有时间限制的同步,可以被的同步的同步是不能的等。
各种方法
1、synchronized方法。
public synchronized void save(){}
2、synchronized代码块。
synchronized(object){ }
3、使用重入锁(ReenreantLock)
public void save(int money) { lock.lock(); try { account += money; } finally { lock.unlock(); } }
4、使用阻塞队列,同步Map(LinkedBlockingQueue,ConcurrentHashMap等)
5、使用原子变量(AtomicInteger等)
各种原理独占锁:是一种悲观锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。
乐观锁:每次不加锁,假设没有冲突就去完成某项操作,如果因为冲突失败就重试,直到成功为止。
CAS:Compare and Swap,典型的乐观锁,使用Cpu的lock cmpxchg指令进行操作。CAS的底层类为Unsafe,Unsafe通过调用JNI(Java Native Interface)代码,在C语言的compareAndSwapInt函数中嵌入汇编指令进行实现,做到了处理器级别的同步。java.util.concurrent包的所有类都基于CAS。
注:volatile保证可见性。参见https://segmentfault.com/a/11...
CAS也有几个缺点:
总结:1、ABA问题,由AtomicStampedReference来解决,即给数据加版本信息。
2、循环时间长开销大。
3、只能保证一个共享变量的原子操作,由AtomicReference来解决,即将多个基本变量整合为一个对象。
synchronized:
所有对象都自动含有单一的锁,JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。每当任务离开时,计数递减,当计数为0的时候,锁被完全释放。synchronized就是基于这个原理,同时synchronized靠某个对象的单一锁技术的次数来判断是否被锁,所以无需(也不能)人工干预锁的获取和释放。
实际上synchronized作用于方法时,锁住的是“this”,作用于静态方法/属性时,锁住的是存在于永久带的CLASS,相当于这个CLASS的全局 锁,锁作用于一般对象时,锁住的是对应代码块。在HotSpot中JVM实现中,锁有个专门的名字:对象监视器。
jdk1.6之前,synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的。而操作系统实现线程之间的切换这就需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间,这就是为什么Synchronized效率低的原因。然而,1.6之后,synchronized已经被做了CAS的优化:具体是这样的,当执行到synchronized代码块时,先对对象头的锁标志位用lock cmpxchg的方式设置成“锁住“状态,释放锁时,在用lock cmpxchg的方式修改对象头的锁标志位为”释放“状态,写操作都立刻写回主内存。JVM会进一步对synchronized时CAS失败的那些线程进行阻塞操作(调用操作系统的信号量)(此段来摘自别处)。也就是先CAS操作,不行的话继而阻塞线程。
ReentrantLock:
Lock不同于synchronized面向对象,它基于栈中的框架而不是某个具体对象,所以Lock只需要在栈里设置锁的开始和结束 (lock和unlock)的地方就行了(人工必须标明),不用关心框架大小对象的变化等等。这么做的好处是Lock能提供无条件的、可轮询的、定时的、 可中断的锁获取操作,相对于synchronized来说,synchronized的锁的获取是释放必须在一个模块里,获取和释放的顺序必须相反,而Lock则可以在不同范围内获取释放,并且顺序无关。
ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。lock是通过代码实现的,要保证锁一定会被释放,就必须将unlock()放到finally{}中。
最后,Atomic无疑是最快的,其次是ConcurrentHashMap等。在较高的并发下,几种方法性能差不多,而在较低并发下,区别就显现出来了,其中synchronized比Lock来的快,基本是两倍的关系。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/67020.html
摘要:的关键字中的块使用关键字进行标记。由于每个类只有一个类对象存在于中,因此全局同时只有一个线程能够进入到同一个类的静态同步方法中。同步代码块使这种期望成为可能。注意同步代码块如何在括号中接受一个对象。相同的实例被传入两个不同的线程实例中。 Java的synchronized块标记一个方法或一个代码块为同步的。synchronized块能用于防止出现竞态条件。 Java的synchroni...
摘要:多线程和并发问题是技术面试中面试官比较喜欢问的问题之一。线程可以被称为轻量级进程。一个守护线程是在后台执行并且不会阻止终止的线程。其他的线程状态还有,和。上下文切换是多任务操作系统和多线程环境的基本特征。 多线程和并发问题是 Java 技术面试中面试官比较喜欢问的问题之一。在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到的问题。(...
摘要:线程可以被称为轻量级进程。一个守护线程是在后台执行并且不会阻止终止的线程。其他的线程状态还有,和。上下文切换是多任务操作系统和多线程环境的基本特征。在的线程中并没有可供任何对象使用的锁和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻译:并发编程网 - 郑旭东 校对:方腾飞 多...
摘要:死亡状态线程退出有可能是正常执行完成也有可能遇见异常退出。类有新建与死亡状态返回其余状态返回判断线程是否存活。线程因某些原因进入阻塞状态。执行同步代码块的过程中执行了当前线程放弃开始睡眠进入就绪状态但是不会释放锁。 【java内存模型简介 JVM中存在一个主存区(Main Memory或Java Heap Memory),Java中所有变量都是存在主存中的,对于所有线程进行共享,而每个...
阅读 1999·2023-04-26 02:15
阅读 2231·2021-11-19 09:40
阅读 937·2021-10-27 14:13
阅读 3220·2021-08-23 09:44
阅读 3572·2019-12-27 12:24
阅读 587·2019-08-30 15:53
阅读 1102·2019-08-30 10:53
阅读 2105·2019-08-26 12:14