java基础系列(八) synchronized关键字

news2024/11/24 6:54:59

一. 认识synchronized

先看一下如下Demo

public class Test {

    public static void main(String[] args) {
        Count obj = new Count();//only one object
        MyThread1 t1 = new MyThread1(obj);
        MyThread2 t2 = new MyThread2(obj);
        t1.start();
        t2.start();
    }
}

class MyThread2 extends Thread {
    Count c;

    MyThread2(Count c) {
        this.c = c;
    }

    public void run() {
        c.printTable(100);
    }
}

class MyThread1 extends Thread {
    Count c;

    MyThread1(Count c) {
        this.c = c;
    }

    public void run() {
        c.printTable(5);
    }


}

class Count {
    //加和不加的打印区别
    public synchronized void printTable(int n) {
        for (int i = 1; i <= 5; i++) {
            System.out.println(n * i);
            try {
                //睡眠四秒
                Thread.sleep(400);
            } catch (Exception e) {
                System.out.println(e);
            }
        }

    }
}

没加 synchronized 关键字打印

5
100
10
200
15
300
20
400
25
500

加了 synchronized 关键字之后的打印

5
10
15
20
25
100
200
300
400
500

1. 理解Java对象中的锁

在理解synchronized之前,我们先简单理解下的概念。在Java中,每个对象都会有一把锁。当多个线程都需要访问对象时,那么就需要通过获得锁来获得许可,只有获得锁的线程才能访问对象,并且其他线程将进入等待状态,等待其他线程释放锁。如下图所示
 

二.  理解synchronized关键字

根据Sun官文文档的描述,synchronized关键字提供了一种预防线程干扰内存一致性错误的简单策略,即如果一个对象对多个线程可见,那么该对象变量(final修饰的除外)的读写都需要通过synchronized来完成。

你可能已经注意到其中的两个关键名词:

  • 线程干扰(Thread Interference):不同线程中运行但作用于相同数据的两个操作交错时,就会发生干扰。这意味着这两个操作由多个步骤组成,并且步骤顺序重叠;
  • 内存一致性错误(Memory Consistency Errors):当不同的线程对应为相同数据的视图不一致时,将发生内存一致性错误。内存一致性错误的原因很复杂,幸运的是,我们不需要详细了解这些原因,所需要的只是避免它们的策略。

从竞态的角度讲,线程干扰对应的是Read-modify-write,而内存一致性错误对应的则是Check-then-act

结合synchronized的概念可以理解为,锁是多线程安全的基础机制,而synchronized是锁机制的一种实现。

三. synchronized的用法

上图中看出 synchronized 可以用来修饰方法 , 静态方法, 代码块

类对象:   说的就是 Test.class 对象

类的实例对象:   比如:  test对象     Test  test = new  Test();

1. 在实例方法中使用synchronized

public class Master {
    //主宰的初始血量
    private int blood = 1000;

    //每次被击打后血量减5
    public int decreaseBlood() {
        blood = blood - 5;
        return blood;
    }

    //通过血量判断主宰是否还存活
    public boolean isAlive() {
        return blood > 0;
    }
}

public synchronized int decreaseBlood() {
       blood = blood - 5;
       return blood;
}

注意这段代码中的synchronized字段,它表示当前方法每次能且仅能有一个线程访问。另外,由于当前方法是实例方法,所以如果该对象存在多个实例的话,不同的实例可以由不同的线程访问,它们之间并无协作关系。

然而,你可能已经想到了,如果当前线程中有两个synchronized方法,不同的线程是否可以访问不同的synchronized方法呢?

答案是:不能

这是因为每个实例内的同步方法,能且仅能有一个线程访问

2. 在静态方法中使用synchronized

public static synchronized int decreaseBlood() {
       blood = blood - 5;
       return blood;
}

与实例方法的synchronized不同,静态方法的synchronized是基于当前方法所属的类,即Master.class,而每个类在虚拟机上有且只有一个类对象。所以,对于同一类而言,每次有且只能有一个线程能访问静态synchronized方法。

当类中包含有多个静态的synchronized方法时,每次也仍然有且只能有一个线程可以访问其中的方法。

注意:synchronized在实例方法和静态方法中的应用可以看出,synchronized方法是否能允许其他线程的进入,取决于synchronized的参数。每个不同的参数,在同一时刻都只允许一个线程访问。基于这样的认知,下面的两种用法就很容易理解了。

3. 在实例方法的代码块中使用synchronized

public int decreaseBlood() {
    synchronized(this) {
       blood = blood - 5;
       return blood;
    }
}

在某些情况下,你不需要在整个方法层面使用synchronized,毕竟这样的方式粒度较大,容易产生阻塞。此时,在代码块中使用synchronized就是非常不错的选择,如上面代码所示。

刚才已经提到,synchronized的并发限制取决于其参数,在上面这段代码中的参数是this,即当前类的实例对象。而在前面的public synchronized int decreaseBlood()中,synchronized的参数也是当前类的实例对象。因此,下面这两段代码是等同的:

public int decreaseBlood() {
    synchronized(this) {
       blood = blood - 5;
       return blood;
    }
}

public synchronized int decreaseBlood() {
       blood = blood - 5;
       return blood;
}

4. 在静态方法的代码块中使用synchronized

同理,下面这两个方法的效果也是等同的。

public static int decreaseBlood() {
    synchronized(Master.class) {
       blood = blood - 5;
       return blood;
    }
}

public static synchronized int decreaseBlood() {
       blood = blood - 5;
       return blood;
}

四. synchronized小结

前面,我们已经介绍了synchronized的几种常见用法,不必死记硬背,你只要记住synchronized可以接受任何非null对象作为参数,而每个参数在同一时刻能且只能允许一个线程访问即可。此外,还有一些具有实际指导意义的Tips你可以注意下:

  1. Java中的synchronized关键字用于解决多线程访问共享资源时的同步,以解决线程干扰内存一致性问题;
  2. 你可以通过 代码块(code block) 或者 方法(method) 来使用synchronized关键字;
  3. synchronized的原理基于对象中的锁,当线程需要进入synchronized修饰的方法或代码块时,它需要先获得锁并在执行结束后释放它;
  4. 当线程进入非静态(non-static)同步方法时,它获得的是对象实例(Object level)的锁。而线程进入静态同步方法时,它所获得的是类实例(Class level)的锁,两者没有必然关系;
  5. 如果synchronized中使用的对象是null,将会抛出NullPointerException错误;
  6. synchronized对方法的性能有一定影响,因为线程要等待获取锁;
  7. 使用synchronized尽量使用代码块,而不是整个方法,以免阻塞整个方法;
  8. 尽量不要使用String类型和原始类型作为参数**。这是因为,JVM在处理字符串、原始类型时会对它们进行优化。比如,你原本是想对不同的字符串进行加锁,然而JVM认为它们是同一个,很显然这不是你想要的结果。

五. 转载文章

转载博客:  并发王者课-青铜04:宝刀屠龙-如何使用synchronized之初体验 - 简书

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/378072.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面试题1-JAVA的执行流程

JAVA的执行流程 分两步,1.翻译 2执行 Java属于两种类型: 编译型和解释型 编译型 ​ 概念: 把源代码翻译成.class文件 >意思是: 把程序员的源代码翻译成虚拟电脑能看得懂的代码 解释型 ​ 概念: 把.class文件进行解析执行 >把翻译后的代码交给虚拟电脑执行指令 执行流程…

揭开Salesforce Accredited Professional证书神秘面纱,到底含金量有多高?

自从Salesforce宣布Accredited Professional计划以来&#xff0c;已经过去了将近两年。这些认证旨在证明备考者在Salesforce平台特定领域的广泛知识&#xff0c;并且仅供Salesforce合作伙伴使用。Accredited Professional中有近40项Salesforce认证&#xff0c;涵盖平台、销售、…

学校机房4大安全隐患,赶紧自查

无论是企业、医院、政府机构还是学校&#xff0c;都有机房。传统机房出现事故时无法及时发现和处理&#xff0c;导致影响范围大&#xff0c;损失严重。 随着信息技术的不断发展&#xff0c;各行业信息化程度不断提升&#xff0c;配套的数据中心机房日益增多&#xff0c;为业务信…

LeetCode 147. 对链表进行插入排序 | C/C++版

LeetCode 147. 对链表进行插入排序 | C语言版LeetCode 147. 对链表进行插入排序题目描述解题思路思路一&#xff1a;使用栈代码实现运行结果参考文章&#xff1a;思路二&#xff1a;减少遍历节点数代码实现运行结果参考文章&#xff1a;[]()LeetCode 147. 对链表进行插入排序 …

Sharding Sphere学习

一、基本概念 1.什么是Sharding Sphere 2.分库分表3.分库分表的方式 4.分库分表应用和问题 5.功能 5.1数据分片 —核心概念 —使用限制 5.2分布式事务 —核心概念 —使用限制 5.3读写分离 —核心概念 —使用限制 5.4高可用 —核心概念 —使用限制 5.5数据库网关 —核心概念…

shield分析

本文仅供学习交流&#xff0c;只提供关键思路不会给出完整代码&#xff0c;严禁用于非法用途&#xff0c;若有侵权请联系我删除&#xff01;技术交流合作请私信&#xff01; 熟练打开Fiddler设置好手机代理&#xff0c;摆弄半天一直抓不到包&#xff0c;应该是小红书监测到了F…

对 Dom 树的理解

什么是 DOM 从网络传给渲染引擎的 HTML 文件字节流是无法直接被渲染引擎理解的&#xff0c;所以要将其转化为渲染引擎能够理解的内部结构&#xff0c;这个结构就是 DOM。 DOM 提供了对 HTML 文档结构化的表述。 在渲染引擎中&#xff0c;DOM 有三个层面的作用&#xff1a; …

攻略 | 6步帮助中小微企业开拓东盟机电产品市场

如何帮助中小微外贸企业在东盟市场拓展机电产品一般贸易&#xff1f;随着全球化的发展&#xff0c;越来越多的中小微外贸企业开始涉足国际贸易。对于机电产品行业而言&#xff0c;东盟市场是一个非常重要的出口目的地。本文将为您介绍如何帮助中小微外贸企业在东盟市场拓展机电…

用一个例子告诉你 怎样使用Spark中RDD的算子

目录 1. 前言 1.1 操作分类 1.2 语法知识 2. transformations 2.1 map 2.2 mapPartitions 2.3 flatMap 2.4 glom 2.5 groupBy 2.6 filter 2.7 sample 2.8 distinct 2.9 coalesce 2.10 repartition 2.11 sortBy 2.12 partitionBy 2.13 reduceByKey 2.14 gro…

从软件的角度看待PCI和PCIE(一)

1.最容易访问的设备是什么&#xff1f; 是内存&#xff01; 要读写内存&#xff0c;知道它的地址就可以了&#xff0c;不需要什么驱动程序&#xff1b; volatile unsigned int *p 0xffff8811; unsigned int val; *p val; val *p;只有内存能这样简单、方便的使用吗&#xf…

python中的序列——笔记

一、介绍 ABC语言时一个致力于为初学者设计编程环境的长达十年的研究项目。 Python也从ABC那里继承了用统一的风格去处理序列数据这一特点。不管是哪种数据结构&#xff0c;字符串、列表、字节序列、数组、XML元素&#xff0c;抑或是数据库查询结果&#xff0c;它们都共用一套…

SD卡损坏了?储存卡恢复数据就靠这3个方法

作为一种方便的储存设备&#xff0c;SD卡在我们的日常生活中使用非常广泛。但是&#xff0c;有时候我们可能会遇到SD卡损坏的情况&#xff0c;这时候里面存储的数据就会受到影响。SD卡里面保存着我们很多重要的数据&#xff0c;有些还是工作必须要使用的。 如果您遇到了这种情…

百度CTO王海峰:深度学习平台+大模型,夯实产业智能化基座

2月27日&#xff0c;中国人工智能学会首届智能融合产业论坛在成都顺利举办。本届论坛由中国人工智能学会&#xff08;CAAI&#xff09;主办&#xff0c;中国人工智能学会智能融合专委会、百度公司、深度学习技术及应用国家工程研究中心和电子科技大学联合承办。中国工程院多名院…

低代码开发平台选型必看指南

低代码开发是近年来逐渐兴起的一种新型软件开发方式。它通过封装常见的软件开发流程和代码&#xff0c;使得非专业的开发者也能够轻松创建复杂的应用程序。这种开发方式已经受到了许多企业的青睐&#xff0c;成为提高生产效率、降低开发成本的一种有效途径。 低代码开发的核心…

TryHackMe-The Great Escape(Docker)

The Great Escape 我们的开发人员创建了一个很棒的新网站。你能冲出沙盒吗&#xff1f; 端口扫描 循例 nmap Web信息收集 robots.txt: /exif-util是文件上传点&#xff0c;但是绕过之后貌似没啥用 在robots.txt当中披露了可能存在.bak.txt&#xff0c;现在我们已知的文件就是…

JavaScript基础语法入门

一. JS简介 JavaScript , 简称JS, JS最初只是为了进行前端页面开发, 但随这后来JS越来越火之后, JS就被赋予了更多的功能, 可以用来开发桌面程序, 手机App, 服务器端的程序等… JS是一种动态类型, 弱类型的脚本语言, 通过解释器运行, 主要在客户端和浏览器上运行, 比如Chrome…

Zeppelin安装

1、下载Zeppelin 下载地址&#xff1a;Download 2.解压 [rootguo147 install]# tar -zxvf zeppelin-0.10.0-bin-all.tgz -C ../soft/ //修改文件名 [rootguo147 soft]# mv zeppelin-0.10.0-bin-all/ zeppelin 3.配置 //进入conf 目录 [rootguo147 conf]# pwd /opt/soft/zepp…

C语言——自定义类型

前言 在之前我们粗略的介绍了一下结构体&#xff0c;但是自定义类型可不仅仅只有结构体类型&#xff0c;今天我们就来介绍自定义类型。 一. 结构体 1.1 结构体的声明 结构体就是将一些值集合在一个结构体变量中&#xff0c;并将这些值称为成员变量&#xff0c;结构体的成员…

Yolov5-Python系列(一)—— 基础入门(yolov5安装、简单使用)

一、资源准备 推荐使用Anconda环境&#xff1a;通过Anaconda则可以通过创造新的虚拟环境解决资源包&#xff08;python库&#xff09;之间冲突问题。 &#xff08;一&#xff09;Anconda安装&#xff1a;https://www.anaconda.com/download &#xff08;二&#xff09;Yolov5 下…

论文《PointTAD》

模型的输出集合&#xff08;Tns&#xff0c;Tne&#xff0c;Cn&#xff09;&#xff0c;Tns是第n个预测动作开始时间&#xff0c;Tne是第n个预测动作结束时间&#xff0c;Cn是第n个预测动作的类别。 模型有三个输入&#xff1a;1.RGB帧 2.可学习的query points 3.query vect…