java synchronized volatile,synchronized在java中的作用
00-1010一、基本特征二。锁定过程偏向于轻量级锁和重量级锁III。其他优化操作锁消除锁粗化IV。可调用接口
00-1010 1.当初是乐观锁定。如果锁频繁冲突,它将被转换为悲观锁。
2.起初,它是一种轻型锁。如果锁持有时间长,会转换成重量级锁。
3.实现轻量级锁时的高概率自旋锁策略。
4.这是一把不公平的锁。
5.这是一把重入锁。
6.不是读写锁
目录
JVM将同步锁分为无锁、有偏锁、轻量级锁和重量级锁。会根据情况依次升级。
00-1010假设男人是锁,女人是线。如果这个线程是唯一使用这个锁的,那么这一男一女就算不领证结婚也能幸福的生活(避免高成本操作)。然而,当女伴出现时,他们也试图争夺男方。这个时候,无论领证结婚的操作多么昂贵,女方都必然要完成这个动作,让女伴放弃。
偏向锁并不是真正的‘锁定’,它只是在对象头做一个‘偏向锁标记’来记录这个锁属于哪个线程。如果将来没有其他线程竞争这个锁,那么就不需要其他同步操作(以避免锁定和解锁的开销)。如果将来有其他线程竞争这个锁(当前锁属于哪个线程,刚刚被记录在锁对象中,所以很容易识别当前申请锁的线程是不是之前记录的那个线程),那么
本质上,锁定偏差相当于‘延迟锁定’。如果不锁定,可以尽量避免不必要的锁定费用。但是,你还是要做好标记,不然你也说不清什么时候真的需要锁。
偏置锁并没有真正被锁定,只是在锁的对象头中记录了一个标记(记录锁所属的线程)。如果没有其他线程参与锁竞争,那么就不会真正执行锁操作,从而减少了程序开销。一旦真正涉及到对方线程竞争,偏向锁状态就会被取消,进入轻量锁状态。
00-1010随着其他线程进入竞争,偏向锁状态被消除,进入轻量锁状态(自适应自旋锁)。这里的轻量级锁是通过CAS实现的。
通过CAS检查和更新内存块(比如null=线程引用)
如果更新成功,则认为锁定成功。
如果更新失败,则认为锁被占用,继续以自旋模式等待(不放弃CPU)。
Spin使CPU保持空闲,这浪费了CPU资源。因此,这里的旋转不会一直继续,而是在一定时间/次数的重试后停止旋转,这称为“自适应”
00-1010如果竞争比较激烈,旋转不能快速获得锁定状态,就会扩展成重量级锁定。这里的重量级锁指的是内核提供的互斥锁。
执行加锁操作,首先进入内核状态。
在内核状态下,确定当前锁是否已被占用。
如果锁未被占用,则锁被成功锁定,并且用户模式被切换回。
如果锁被占用,锁定将失败。此时线程进入锁的等待队列,挂起,等待被操作系统唤醒。
经过一系列的沧桑,锁被其他线程释放,操作系统记住了挂起的线程,于是唤醒线程,试图重新获得锁。
一、基本特点
00-1010编译器JVM确定是否可以消除锁。如果有,可以直接淘汰
有些应用程序使用同步代码,但它不在多线程环境中(例如StringBuffer)
string buffer sb=new string buffer();某人追加( a );某人追加( b );某人追加( c );某人追加( d );此时,每个追加调用都涉及锁定和解锁。但是,如果这段代码只在单线程中执行,这些锁定和解锁操作就没有必要了,浪费了一些资源。
00-1010如果一个逻辑段中出现多个锁和解锁,编译器JVM会自动粗化锁。
领导,给下属交代工作任务。
模式1 :
打电话,解释任务1,然后挂断。
打电话,解释任务2,然后挂断。
打电话,解释任务3,然后挂断。
模式2 :
打电话,说明任务1,任务2,任务3,挂电话。
s="maodian">
四、Callable 接口
Callable 是什么
Callable 是一个 interface . 相当于把线程封装了一个 "返回值". 方便程序猿借助多线程的方式计算 结果.
Callable 和 Runnable 相对, 都是描述一个 "任务". Callable 描述的是带有返回值的任务, Runnable 描述的是不带返回值的任务.Callable 通常需要搭配 FutureTask 来使用. FutureTask 用来保存 Callable 的返回结果. 因为 Callable 往往是在另一个线程中执行的, 啥时候执行完并不确定. FutureTask 就可以负责这个等待结果出来的工作.
代码示例: 创建线程计算 1 + 2 + 3 + ... + 1000, 不使用 Callable 版本
public class Text { static class Result{ public int sum = 0; public Object locker = new Object(); } public static void main(String[] args) throws InterruptedException { Result result = new Result(); Thread t = new Thread(){ @Override public void run() { int sum = 0; for (int i = 0; i <=10000; i++){ sum += i; } result.sum = sum; synchronized (result.locker){ result.locker.notify(); } } }; t.start(); synchronized (result.locker){ while (result.sum == 0){ result.locker.wait(); } } System.out.println(result.sum); }}
代码示例: 创建线程计算 1 + 2 + 3 + ... + 1000, 使用 Callable 版本
import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask; public class Text1 { public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() throws Exception { int sum = 0; for (int i = 0; i <=1000; i++){ sum += i; } return sum; } }; //由于Thread不能直接传一个callable实例,就需要一个辅助类来包装 FutureTask<Integer> futureTask = new FutureTask<>(callable); Thread t = new Thread(futureTask); t.start(); //尝试在主线程获取结果 //如果FutureTask中的结果还没生成。此时就会阻塞等待 //一直等到最终的线程把这个结果算出来,get返回 Integer result = futureTask.get(); System.out.println(result); }}
到此这篇关于Java 深入浅出分析Synchronized原理与Callable接口的文章就介绍到这了,更多相关Java Synchronized 内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。