首页 > 其他分享 >07.synchronized都问啥?

07.synchronized都问啥?

时间:2023-01-05 21:02:06浏览次数:62  
标签:07 Thread t2 t1 synchronized new SynchronizedDemo

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

如果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,Thread,t2,t1,synchronized,new,SynchronizedDemo
From: https://www.cnblogs.com/wyz1994/p/17028834.html

相关文章

  • 米尔国产T507-H开发板之Android SDK说明
        安卓系统作为目前世界上最受欢迎的移动操作系统,它可以在大量的设备上使用,它正在接管平板电脑、汽车、智能电视、可穿戴设备、家用电器、游戏机等市场,它为嵌入式平台......
  • IEC60079-11 附录3电气间隙和爬电距离的计算-转载
    (24条消息)IEC60079-11附录3电气间隙和爬电距离的计算_dylanZheng的博客-CSDN博客_爬电距离与电气间隙计算公式......
  • Java synchronized
    synchronized是java提供线程间同步的重要机制保证在同一时刻,被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的效果java内存模型:先通过一个生产者消费者例......
  • 网页游戏为什么容易赚钱?(From:07073)
    网页游戏为什么容易赚钱?商业就是这样2012-10-0817:47作者:​​董晓常​​我们刚刚经历了惊讶的9月,现在又在享受一个可能更加惊讶的10月。从商业上来说,一个让人惊讶......
  • 【题解】CF1073G Yet Another LCP Problem
    题面很清楚,不概括了。思路后缀树+树剖。套路题。看到lcp考虑转化成后缀树上求lca,这里可以用SAM构造反串的parenttree解撅(f**kuukk)于是问题转化成:每次给......
  • 告警日志中报错ORA-07445 kkqstcrf
    问题描述:数据库例行巡检时发现告警日志中报错ORA-07445kkqstcrf,如下所示:数据库:oracle11.2.0.1告警日志:SunDec2522:08:222022BeginautomaticSQLTuningAdvisorrun......
  • 【Vue】常见问题(一)找不到模块“./App.vue”或其相应的类型声明。ts(2307)
    vue+vite项目,打开找不到模块  解决办法:在根目录下创建jsconfig.json文件,进行如下配置:  {"compilerOptions":{"baseUrl":"./","pat......
  • python常识系列07-->python利用xlwt写入excel文件
     前言读书之法,在循序而渐进,熟读而精思。——朱熹抽空又来写一篇,毕竟知识在于分享!一、xlwt模块是什么python第三方工具包,用于往excel中写入数据;(ps:只能创建新表格,不能修......
  • Spark详解(07-1) - SparkStreaming案例实操
    Spark详解(07-1)-SparkStreaming案例实操环境准备pom文件<dependencies>    <dependency>        <groupId>org.apache.spark</groupId>      ......
  • NC25064 [USACO 2007 Mar G]Ranking the Cows
    题目链接题目题目描述EachofFarmerJohn'sNcows(1≤N≤1,000)producesmilkatadifferentpositiverate,andFJwouldliketoorderhiscowsaccording......