一、概念

利用锁机制实现线程同步,synchronized关键字的底层交由了JVM通过C++来实现

Java中的锁有两大特性:

  • 互斥性

    • 同一时间,只允许一个线程持有某个对象锁。
  • 可见性
    • 锁释放前,线程对变量的修改,后面获得锁的线程可见。

可见性

JMM关于synchronized的两条规定:

  1. 线程解锁前,必须把共享变量的最新值刷新到主内存中

  2. 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新获取最新的值(注意:加锁与解锁需要是同一把锁)

通过以上两点,可以看到synchronized能够实现可见性。

二、用法

synchronized修饰位置与锁的关系

  • 同步方法 —— 对象锁,当前实例对象
  • 静态同步方法 —— 类对象锁,当前对象的Class对象
  • 同步方法块 —— 对象锁,synchonized括号里配置的对象

public class SynchronizedDemo { private static int m = 0; private Object obj = new Object(); /**
* 修饰非静态方法
*/
public synchronized void m1() {
sleep(2);
m++;
} /**
* 修饰静态方法
*/
public synchronized static void m2() {
sleep(2);
m++;
} /**
* 同步代码块,对对象加锁
*/
public synchronized void m3() {
synchronized (this) {
sleep(2);
m++;
}
} public synchronized void m4() {
synchronized (obj) {
sleep(2);
m++;
}
} /**
* 同步代码块,对类加锁
*/
public synchronized void m5() {
synchronized (SynchronizedDemo.class) {
sleep(2);
m++;
}
} public static void sleep(int second) { try {
Thread.sleep(second * 1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }

三、面试问题

同一个对象在A、B两个线程中分别访问该对象的两个同步方法writer和reader,是否会产生互斥?


class LockDemo{ int a = 0; public synchronized void writer(){
sleep(10);
a++;
} public synchronized void reader(){
int i = a;
} public static void main(String[] args) { Test test = new Test();
new Thread(() -> {
test.writer();
}).start(); sleep(1); new Thread(() -> {
test.reader();
}).start(); } }

答案:会。因为synchronized修饰的是方法,锁是对象锁,默认当前的对象作为锁的对象。只有当A释放锁之后,B才会获得对象的锁。

(1)如果是换成是不同对象呢?

不会互斥,因为锁的是对象,而不是方法

(2)如果writer、reader方法加上static修饰,两个线程中,类直接调用两个方法呢?

会互斥,因为锁的是Class对象。

(3)如果writer方法用static修饰,reader方法不用呢?

不会互斥。因为一个是对象锁,一个是Class对象锁,锁的类型不同。

Java核心复习——synchronized的更多相关文章

  1. Java核心复习—— 原子性、有序性与Happens-Before

    一. 产生并发Bug的源头 可见性 缓存导致的可见性问题 原子性 线程切换带来的原子性问题 有序性 编译优化带来的有序性问题 上面讲到了 volatile 与可见性,本章再主要讲下原子性.有序性与Ha ...

  2. Java核心复习——J.U.C AbstractQueuedSynchronizer

    第一眼看到AbstractQueuedSynchronizer,通常都会有这几个问题. AbstractQueuedSynchronizer为什么要搞这么一个类? 这个类是干什么的.有什么用? 这个类 ...

  3. Java核心复习——线程池ThreadPoolExecutor源码分析

    一.线程池的介绍 线程池一种性能优化的重要手段.优化点在于创建线程和销毁线程会带来资源和时间上的消耗,而且线程池可以对线程进行管理,则可以减少这种损耗. 使用线程池的好处如下: 降低资源的消耗 提高响 ...

  4. Java核心复习—— ThreadLocal源码分析

    ThreadLocal,叫做线程本地存储,也可以叫做线程本地变量.ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量. 一.如何使用 class Acce ...

  5. Java核心复习 —— J.U.C 并发工具类

    一.CountDownLatch 文档描述 A synchronization aid that allows one or more threads to wait until* a set of ...

  6. Java核心复习—— volatile 与可见性

    一.介绍 volatile保证共享变量的"可见性".可见性指的是当一个线程修改变量时,另一个线程能读到这个修改的值. 这里就要提出几个问题. 问题1:为什么一个线程修改时,另一个线 ...

  7. Java核心复习——CompletableFuture

    介绍 JDK1.8引入CompletableFuture类. 使用方法 public class CompletableFutureTest { private static ExecutorServ ...

  8. Java核心复习——J.U.C LinkedBlockingQueue源码分析

    参考文档 LinkedBlockingQueue和ArrayBlockingQueue的异同

  9. Java核心复习——J.U.C ArrayBlockingQueue源码分析

    介绍 依赖关系 源码 构造方法 public ArrayBlockingQueue(int capacity) { this(capacity, false);//默认构造非公平的有界队列 } pub ...

随机推荐

  1. Android 在同一台设备上安装多个同一项目的apk

    如果设备上已经安装了一个apk,再次安装这个apk就会提示覆盖前面的应用 解决办法: 方法一:手动改包名 不好改,改了几次都不成功(可能是代码在svn管理的原因,改完后文件夹里的代码就没了),确实不实 ...

  2. 深入浅出Git(偏向理论)

    目录 一.理论概述 1. 什么是Git 版本控制系统分类 2. GitLab和GitHub是什么 3.Git功能 二.结合具体命令了解其工作 1.环境 2.部署 Git仓库的使用 简单命令解释 Git ...

  3. Oracle死锁处理实例

    Oracle死锁常规语句 1.查询Oracle死锁常规语句 SELECT l.session_id sid, s.serial#, l.locked_mode,l.oracle_username, l ...

  4. javascript之位置

    1.offset()获取匹配元素在相对浏览器窗口的偏移量 返回一个对象,包括两个属性.left:相对浏览器窗口左边的距离.top:相对浏览器顶部的距离.  $("#div1").o ...

  5. 记录java+testng运行selenium(四)--- 运行代码

    涉及的文件有: .\medical\BusinessFile.java :实例化excel及xml文件操作对象以及将list变成Map .\medical\manual\business\LoginB ...

  6. nginx编译安装和功能介绍

    nginx介绍 nginx: engine X,是由1994年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯rambler.ru公司开发的,开发工作最早从2002年开始,第一次公开发布时间是2004 ...

  7. Linux命令——logger

    参考:How to use logger on Linux Difference between /var/log/messages, /var/log/syslog, and /var/log/ke ...

  8. windows 数据备份

    xcopy 数据目录   备份目录  /e /c /q /h /r /y at 00:00 /every:M,T,W,Th,F,S,Su d:\批处理文件名

  9. RT-Thread--线程间通信

    线程中通信 在裸机编程中,经常会使用全局变量进行功能间的通信,如某些功能可能由于一些操作而改变全局变量的值,另一个功能对此全局变量进行读取,根据读取到的全局变量值执行相应的动作,达到通信协作的目的: ...

  10. 锁、threading.local、线程池

    一.锁 Lock(1次放1个) 什么时候用到锁: 线程安全,多线程操作时,内部会让所有线程排队处理.如:list.dict.queue 线程不安全, import threading import t ...