大家好,我是王有志。关注王有志,一起聊技术,聊游戏,从北漂生活谈到国际风云。最近搞了个抽奖送书的活动,欢迎点击链接参与。

如果Java面试有什么是必问的,synchronized必定占据一席之地。初出茅庐时synchronized的用法,成长后synchronized的原理,可谓是Java工程师的“一生之敌”。

synchronized都问啥?

按照惯例,先来看synchronized的常见问题:

根据统计数据可以总结出synchronized的5大考点:

  • synchronized的使用方式:

    • synchronized是什么?
    • synchronized怎么用?
    • 不同用法都有什么效果?
  • synchronized的实现原理:
    • synchronized的特性是如何实现的?
    • synchronized锁升级的原理。

今天我们先来看synchronized的基础部分。

synchronized是什么?

synchronized是Java中的关键字,提供了原生同步机制,实现互斥语义和可见性保证,通常称为互斥锁

  • 互斥指的是,当线程获取到锁后,其它试图获取锁的线程只能阻塞;
  • 可见性指的是,synchronized修饰的语句内修改共享变量可以立即被其它线程获取。

互斥就意味着,同一时间只有一个线程执行synchronized修饰的代码,那么:

  • 无论怎么重排序,都会遵循as-if-serial语义,因此synchronized中不存在有序性问题;
  • 不主动释放锁,其他线程无法执行synchronized中代码,无需考虑原子性问题。

因此synchronized互斥就代表了对有序性问题和原子性问题的保证。不过前提是JSR-133中反复提到的correctly synchronized(正确的同步),举个例子:

public class IncorrectlySynchronized {

    private Integer count = 0;

    public  void add() {
synchronized (count) {
count++;
}
} public static void main(String[] args) throws InterruptedException {
IncorrectlySynchronized incorrectlySynchronized = new IncorrectlySynchronized();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
incorrectlySynchronized.add();
}
});
Thread t2 = new Thread(()-> {
for (int i = 0; i < 10000; i++) {
incorrectlySynchronized.add();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(incorrectlySynchronized.count);
}
}

看似该加synchronized的地方都加了,但是结果却会出乎意料,这就典型的错误同步的例子。

synchronized锁什么?

既然是锁,那么synchronized锁的是什么呢?

《The Java Language Specification》中描述(节选)到:

Each object in Java is associated with a monitor, which a thread can lock or unlock.

The synchronized statement computes a reference to an object; it then attempts to perform a lock action on that object's monitor and does not proceed further until the lock action has successfully completed.

Java中每个对象都与一个监视器关联,线程可以锁定或者解锁该监视器。synchronized语句尝试锁定与对象关联的监视器,锁定成功后才可以继续执行

通常,我们将synchronized锁定与对象关联的监视器理解为synchronized锁定对象本身

在我们知道synchronized锁什么后,再去看用法,很多内容就会一目了然了。

synchronized怎么用?

作为关键字,synchronized有两种用法:

  • 修饰代码块
  • 修饰方法
    • 修饰成员方法
    • 修饰静态方法

之前有个同事特别迷信“背技术”,为了区分不同用法的效果,背了某机构的“线程八锁”,但每过一段时间就会忘记。

其实,知道了synchronized锁什么,不同用法的效果自然就出来了,看一个例子:

public class SynchronizedDemo {
public static void main(String[] args) throws InterruptedException {
SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
Thread t1 = new Thread(synchronizedDemo::lockMemberMethod1);
Thread t2 = new Thread(synchronizedDemo::lockMemberMethod2);
t1.start();
// 确保t1先执行
TimeUnit.SECONDS.sleep(1);
t2.start();
} private synchronized void lockMemberMethod1() {
System.out.println("方法1");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
} private synchronized void lockMemberMethod2() {
System.out.println("方法2");
}
}

通过实例变量调用成员方法时,会隐式的传递this。这个例子中,t1和t2想锁定的监视器是谁的?synchronizedDemo对象的。t1先获取到,那么t2只能等待t1释放后再获取了。

那此时的锁定范围是什么?synchronizedDemo对象。

修改下代码:

public static void main(String[] args) throws InterruptedException {
SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
SynchronizedDemo synchronizedDemo2 = new SynchronizedDemo();
Thread t1 = new Thread(synchronizedDemo::lockMemberMethod1);
Thread t2 = new Thread(synchronizedDemo2::lockMemberMethod2);
t1.start();
t2.start();
}

t2不再争夺synchronizedDemo而是争夺synchronizedDemo2,结果上也能看出t1和t2之间不存在竞争关系。

那么使用synchronized修饰静态方法和代码块是什么效果呢?

private static synchronized void lockStaticMethod() {
System.out.println("静态方法!");
} private void lockCodeBlock(int count) {
synchronized (this) {
System.out.println("成员方法的代码块!");
}
}

使用synchronized修饰静态方法,锁定的对象是SynchronizedDemo.class。所有SynchronizedDemo的实例对象共用同一个SynchronizedDemo.class,同一时间不同变量,只有一个线程可以执行lockStaticMethod方法。

至于synchronized修饰代码块,就比较灵活了,括号中是谁就锁定谁。如果是this就锁定实例变量,如果是SynchronizedDemo.class效果就和修饰静态方法一样。

至于前面错误的同步的例子,它的问题是count对象在不断变化(Integer实现相关)的,因此synchronized锁定的并不是同一个对象。

结语

今天的内容非常基础,难度也不大。

重点可以放在synchronized锁什么的部分,以及是如何推导出synchronized不同用法产生的不同效果的。这样的方式更接近于问题的本质,也能更好的举一反三,而不是死记硬背“线程八锁”这种东西。


好了,今天就到这里了,Bye~~

07.synchronized都问啥?的更多相关文章

  1. Aaron Swartz – 互联网天才开挂的人生历程:每时每刻都问自己,现在这世界有什么最重要的事是我能参与去做的?

    Aaron说的一句话让我挺有感触的-- 相信你应该真的每时每刻都问自己,现在这世界有什么最重要的事是我能参与去做的? 如果你没在做那最重要的事,那又是为什么? 1986年11月8日,有个叫Aaron ...

  2. 阿里面试Java程序员都问些什么?

    刚开始也是小白,也是一步步成成起来的.需要提的一点是,你将来是需要靠这个吃饭的,所以请对找工作保持十二分的热情,而且越早准备越好. 阿里一面 一面是在上午9点多接到支付宝的面试电话的,因为很期望能够尽 ...

  3. 关于微信小程序,你想知道的他们都问了

    微信公开课深圳站小程序专场刚刚结束,大家通过"微信公开课+"互动小程序提出了许多问题.我们筛选了后台问得最多的九个问题进行解答,快来看看这里有没有你想要的答案吧! @谢杨:小程序是 ...

  4. Java多线程系列 基础篇07 synchronized底层优化

    转载 http://www.cnblogs.com/paddix/ 作者:liuxiaopeng http://www.infoq.com/cn/articles/java-se-16-synchro ...

  5. 2019年Spring Boot面试都问了什么?快看看这22道面试题!

    Spring Boot 面试题 1.什么是 Spring Boot? 2.Spring Boot 有哪些优点? 3.什么是 JavaConfig? 4.如何重新加载 Spring Boot 上的更改, ...

  6. 2019年JVM面试都问了什么?快看看这22道面试题!(附答案解析)

    一. Java 类加载过程? Java 类加载需要经历一下 7 个过程: 1. 加载 加载是类加载的第一个过程,在这个阶段,将完成一下三件事情: • 通过一个类的全限定名获取该类的二进制流. • 将该 ...

  7. 月薪20k+的Android面试都问些什么?(含答案)

    金九银十跳槽季接近尾声了,可是今年由于疫情的影响仍然不太好找工作,相信大家肯定急需一套Android面试宝典,下面就分享给大家我珍藏已久的Android高阶面试宝典,供大家学习 ! 1.自定义Hand ...

  8. Java中的Lock与synchronized

    并发编程学习笔记之Lock与synchronized 一.什么是可重入锁 Lcok在Java中是一个接口,一般在面试问题中问到的可能是ReentrantLock与synchronized的区别.Ree ...

  9. 解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度-美团)

    还有其他的锁,如果想要了解,参考:JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁, 用synchronized实现ReentrantLock 美团面试题参考:使用synchronized ...

  10. Hashtable数据存储结构-遍历规则,Hash类型的复杂度为啥都是O(1)-源码分析

    Hashtable 是一个很常见的数据结构类型,前段时间阿里的面试官说只要搞懂了HashTable,hashMap,HashSet,treeMap,treeSet这几个数据结构,阿里的数据结构面试没问 ...

随机推荐

  1. PaddleOCR-EAST

    目录 EAST Abstract Train PreProcess Architecture Backbone Neck Head Loss Dice Loss SmoothL1 Loss Infer ...

  2. Optimize(优化实验)

    十大优化法则 1.更快(本课程重点!) 2.更省(存储空间.运行空间) 3.更美(UI 交互) 4.更正确(本课程重点!各种条件下) 5.更可靠 6.可移植 7.更强大(功能) 8.更方便(使用) 9 ...

  3. 十一、Pod的健康检查-探针

    Pod 的健康检查-探针 一.Pod 的健康检查-探针 1.1.探针基本概念 ​探针是由 kubelet 对容器执行的定期诊断.要执行诊断,kubelet 调用由容器实现的 Handler 有三种类型 ...

  4. 机器学习中in-domine, out-domine的区别

    in-domine 为域内数据,即为训练模型时使用的数据: out-domine 为域外数据,即为检验模型时使用的数据.

  5. 【题解】CF1659E AND-MEX Walk

    题目传送门 位运算 设题目中序列 \(w_1,w_1 \& w_2,w_1 \& w_2 \& w_3,\dots,w_1 \& w_2 \& \dots \& ...

  6. js和jquery页面初始化加载函数的方法及顺序

    运行下面代码.弹出A.B.C.D.E的顺序:A=B=C>D=E. <html> <head> <title>首页</title> <scri ...

  7. day02-实现01

    实现01 1.实现任务阶段1 编写mytomcat,该服务器能给浏览器返回"你好,我是服务器!"的简单信息. 根据之前的tomcat框架整体分析,我们将浏览器发送请求,tomcat ...

  8. kubeedge的云边协同通道

    1. CloudHub安全认证流程 2. EdgeHub安全认证流程 3. Edged节点纳管

  9. mysql查询结果拼接树结构(树节点的移动)

    mysql查询结果拼接树结构(树节点的移动) 思路:单表内查询全部数据,在业务层内递归拼接树结构. 前端用的是element的Tree 树形控件: 树结构实体: @Data @AllArgsConst ...

  10. Android Studio 卡在download fastutil下载慢

    需要替换国内镜像,现在阿里云地址已经更新了.需要使用新的地址.可以参考 https://developer.aliyun.com/mvn/guide 以下是更改buil.gradle文件的代码 // ...