Java中Synchronized关键字的基本使用方法

news2024/10/1 19:22:48

Java中Synchronized关键字的基本使用方法

1.简介
Synchronized是java的关键字,synchronized可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作),synchronized可保证一个线程的变化(主要是共享数据的变化)被其他线程所看到。

Synchronized关键字细分的话,主要的修饰对象有以下几种:
1)修饰一个代码块,其作用的范围是Synchronized后面{}括起来的代码,作用的对象是调用这个代码块的实例对象,对给定实例对象加锁,进入同步代码块之前要获得给定实例对象的锁。如:

public void test() {
		// 同步代码块,this为给定实例对象
        synchronized (this) {
           // 同步代码块中的内容
        }
}

2)修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的实例对象;如:

// 同步方法
public synchronized void test() {
		
}

3)修饰一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有实例对象。如:

public synchronized static void test() {
		
}

4)修饰一个类,其作用的范围是synchronized后面{}括起来的部分,作用的对象是这个类的所有实例对象,类似于1与3的结合,与1相比,1只作用于对象的单个实例,而4则作用于对象的全部实例。如:

public void test() {
		// 同步代码块,作用的对象为Test类的所有实例对象。
        synchronized (Test.Class) {
           // 同步代码块中的内容
        }
}

2.Synchronized修饰代码块

public class SyncThread implements Runnable {

    public static void main(String[] args) {
        SyncThread syncThread = new SyncThread();
        Thread thread1 = new Thread(syncThread, "SyncThread1");
        Thread thread2 = new Thread(syncThread, "SyncThread2");
        thread1.start();
        thread2.start();
    }

    private static int count;

    public SyncThread() {
        count = 0;
    }

    public void run() {
    	// 其他代码。。。
        //一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() + ":" + (count++));
                    Thread.sleep(100);
                    notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
       // 其他代码。。。
    }
    public int getCount() {
        return count;
    }
}

在这里插入图片描述

当两个并发线程(thread1和thread2)访问同一个实例对象(syncThread)中的synchronized代码块时,在同一时间只能有一个线程可以执行, 另一个线程会收到阻塞,必须等待当前线程执行完整个代码块以后才能接着执行该代码块。
Thread1和thread2是互斥的,因为在执行synchronized代码块时会锁定当前的实例对象,只有执行完该代码块才能释放该对象锁,下一个线程才能的到并执行并锁定该对象。

我们可以做一个对比,接下来稍微修改一下实例对象(syncThread):

        SyncThread syncThread1 = new SyncThread();
        SyncThread syncThread2 = new SyncThread();
        Thread thread1 = new Thread(syncThread1, "SyncThread1");
        Thread thread2 = new Thread(syncThread2, "SyncThread2");
        thread1.start();
        thread2.start();

在这里插入图片描述
线程thread1和线程thread2分别创建了两个SyncThread的实例对象syncThread1和syncThread2,线程thread1执行的是syncThread1对象中的synchronized代码块,而线程thread2执行的是syncThread2对象中的synchronized代码块。
我们知道synchronized锁定的是实例对象,这时会有两把锁分别锁定SyncThread这个对象的syncThread1实例和syncThread2实例,这是两把锁,所以互不干扰的,不形成互斥,两个线程可以同时执行。

3.Synchronized修饰方法

public class SyncThread implements Runnable {

    public static void main(String[] args) {
        SyncThread syncThread = new SyncThread();
        Thread thread1 = new Thread(syncThread, "SyncThread1");
        Thread thread2 = new Thread(syncThread, "SyncThread2");
        thread1.start();
        thread2.start();
    }

    private static int count;

    public SyncThread() {
        count = 0;
    }

    public synchronized void method() {
        for (int i = 0; i < 5; i++) {
            try {
                System.out.println(Thread.currentThread().getName() + ":" + (count++));
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void run() {
		method();
    }
    public int getCount() {
        return count;
    }
}

synchronized修饰方法和synchronized修饰代码块本质其实没什么区别,synchronized修饰代码块是因为,在一些情况下,我们编写的方法,方法体可能比较大,同时可能存在一些比较耗时的操作,而需要同步的代码又只有一小部分,如果直接对整个方法进行同步操作,可能会造成不小的损失,所以我们使用同步代码块的方式对需要同步的代码进行包裹,这样就无需对整个方法进行同步操作了。

synchronized修饰方法可以参照上文的synchronized修饰代码块。

4.Synchronized修饰静态方法

public class SyncThread implements Runnable {

    public static void main(String[] args) {
        SyncThread syncThread1 = new SyncThread();
        SyncThread syncThread2 = new SyncThread();
        Thread thread1 = new Thread(syncThread1, "SyncThread1");
        Thread thread2 = new Thread(syncThread2, "SyncThread2");
        thread1.start();
        thread2.start();
    }

    private static int count;

    public SyncThread() {
        count = 0;
    }

    public static synchronized void method() {
        for (int i = 0; i < 5; i++) {
            try {
                System.out.println(Thread.currentThread().getName() + ":" + (count++));
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void run() {
		method();
    }
    public int getCount() {
        return count;
    }
}

在这里插入图片描述
当synchronized作用于静态方法时,就是相当于当前类的class对象锁,作用于类的所有实例对象,静态方法不专属于任何一个实例对象。
需要注意的是如果一个线程A调用一个实例对象的非static synchronized方法,而线程B需要调用这个实例对象所属类的静态synchronized方法,是允许的,不会发生互斥现象,因为访问静态synchronized方法占用的锁是类的class对象,而访问非静态synchronized方法占用的锁是当前类的实例对象锁。如:

public class SyncThread implements Runnable{

    public static void main(String[] args) {
        Thread thread1 = new Thread(new SyncThread(), "SyncThread1");
        Thread thread2 = new Thread(new SyncThread(), "SyncThread2");
        thread1.start();
        thread2.start();
    }

    private static int count;

    public SyncThread() {
        count = 0;
    }

    public static synchronized void method() {
            for (int i = 0; i < 5; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() + ":" + (count++));
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }

    public synchronized void test(){
        for (int i = 0; i < 5; i++) {
            try {
                System.out.println(Thread.currentThread().getName() + ":" + (count++));
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void run() {
        String threadName = Thread.currentThread().getName();
        if (threadName.equals("SyncThread1")) {
            method();
        } else if (threadName.equals("SyncThread2")) {
            test();
        }
    }

}

在这里插入图片描述

5.Synchronized修饰类

public class SyncThread implements Runnable {

    public static void main(String[] args) {
        SyncThread syncThread = new SyncThread();
        Thread thread1 = new Thread(syncThread, "SyncThread1");
        Thread thread2 = new Thread(syncThread, "SyncThread2");
        thread1.start();
        thread2.start();
    }

    private static int count;

    public SyncThread() {
        count = 0;
    }

    public void method() {
    	synchronized (SyncThread.class) {
	        for (int i = 0; i < 5; i++) {
	            try {
	                System.out.println(Thread.currentThread().getName() + ":" + (count++));
	                Thread.sleep(100);
	            } catch (InterruptedException e) {
	                e.printStackTrace();
	            }
	        }
        }
    }

    public void run() {
		method();
    }
    public int getCount() {
        return count;
    }
}

synchronized修饰类和synchronized修饰静态方法本质其实没什么区别,相当于synchronized修饰代码块,但是其作用范围是类的全部实例对象。

synchronized修饰类可以参照上文的synchronized修饰静态方法。

6.总结一下:
synchronized虽然细分修饰了4种对象:代码块,方法,静态方法,类
但是其本质锁住的对象只有两种:调用的类的实例对象,类的全部实例对象。
代码块和方法只锁住了调用的类的实例对象,我们可以同时调用该类中非synchronized方法。
静态方法和类锁住了类的全部实例对象,我们可以同时调用该类的非静态synchronized方法。

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

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

相关文章

动态规划【Day01】| 669 · 换硬币、114 · 不同的路径、116 · 跳跃游戏

秘诀&#xff1a;确定状态转移方程初始条件和边界情况计算顺序 669 换硬币 669 换硬币 题目描述&#xff1a; 给出不同面额的硬币以及一个总金额. 写一个方法来计算给出的总金额可以换取的最少的硬币数量. 如果已有硬币的任意组合均无法与总金额面额相等, 那么返回 -1。 样…

元宇宙将如何彻底改变 K-12 和高等教育

欢迎来到Hubbleverse &#x1f30d; 关注我们 关注宇宙新鲜事 &#x1f4cc; 预计阅读时长&#xff1a;9分钟 本文仅代表作者个人观点&#xff0c;不代表平台意见&#xff0c;不构成投资建议。 想象一下&#xff0c;你将作为一个微小的细胞去参观人类的循环系统。这只是元宇…

基于django搭建简单的个人博客

文章目录第一步、在Ubuntu中安装虚拟环境并进入第二步、安装blog所需要的包&#xff0c;在requirements.txt中安装mysqlclient可能会报错&#xff0c;输入下列命令后在安装即可成功第三步、创建好数据库&#xff0c;把测试数据导入第四步、修改DjangoBlog包中 settings中数据库…

企业如何做好EHS环境健康安全管理?

目前随着传统制造业企业安全管理制度的落实&#xff0c;工人的安全意识得到很大的提升&#xff0c;但企业内部的安全管理制度并不能完全避免意外发生。如受限空间人员闯入、特种设备伤人、人员作业不规范、危化品泄露、仓储车间发生火情、有毒有害气体超标等一系列安全隐患。对…

leaflet 修改popup的样式,个性化弹窗(069)

第069个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中修改popup组件的样式,个性化弹窗。主要方法是更改css, 中增加custom-popup类名,style的样式要做穿透处理 >>>.具体方法请参考源代码。 直接复制下面的 vue+leaflet源代码,操作2分钟即可运行实…

使用Python绘制股票CCI指标曲线

本文使用Python语言绘制一只股票的CCI&#xff08;Commodity channel index&#xff09;曲线&#xff0c;论文参考《Commodity channel index: Tool for trading cyclic trends》&#xff0c;该指标可以用来测量股价、外汇或者贵金属交易是否已超出常态分布范围&#xff0c;​ …

MYSQL数据库-主从复制(原理及搭建)

文章目录1 概述2 原理3 搭建3.1 主库配置3.2 从库配置1 概述 主从复制是指将主数据库的DDL和 DML操作通过二进制日志传到从库服务器中&#xff0c;然后在从库上对这些日志重新执行(也叫重做)&#xff0c;从而使得从库和主库的数据保持同步。 MySQL支持一台主库同时向多台从库进…

周立功ZCANPRO基础使用教程

软件及驱动安装 1.安装ZCANPRO软件 ZCANPRO软件官网:USB接口CAN卡-广州致远电子股份有限公司 点击资料下载: 2.安装驱动 本人使用的USBCANFD-200U设备,大家可根据自己的设备下载对应的驱动。 设备驱动官网链接:https://manual.zlg.cn/web/#/42/2462 软件使用教程 1.选择…

嵌入式开发:你需要知道的5种简单

传达嵌入式软件体系结构设计意图通常伴随着基于嵌入式开发人员经验的假设。你可以从资源受限的基于微控制器的系统的角度来看架构设计。如何设计架构将取决于系统的嵌入式软件分类。有许多不同的方法可以对嵌入式软件进行分类。我发现有五种简单的嵌入式软件分类可以帮助我调整…

字符串内存分配

涉及三块区域&#xff1a;栈&#xff0c;堆&#xff0c;字符串常量池&#xff08;jdk1.7之前在方法区&#xff0c;jdk1.7之后在堆中&#xff09; 关于字符串常量池到底在不在堆中&#xff1a; jdk1.6及以前&#xff0c;方法区独立存在&#xff08;不在堆里面&#xff09;&…

达梦数据库监控指标

一、达梦数据库监控指标 数据库常见性能指标主要有:当前登录数、非阻塞锁数、当前死锁数、阻塞锁数、当前锁数、会话数等内容,如下图所示。 注意:以下是 达梦数据库监控所需要的指标,具体根据需要监控哪些、超阈值而定。 1.1 新建主机群组 1.2 新建模板 1.3 创建主机 1.…

【Airplay_BCT】Bonjour API架构

Bonjour API 架构 OS X 和 iOS 为 Bonjour 服务应用程序提供了多层应用程序编程接口 (API)&#xff1a; Foundation 框架中的 NSNetService 和 NSNetServiceBrowser 类&#xff1b; CFNetServices&#xff0c;Core Services 中 CFNetwork 框架的一部分&#xff1b; Java 的 DN…

如何在现实场景中随心放置AR虚拟对象?

随着AR的发展和电子设备的普及&#xff0c;人们在生活中使用AR技术的门槛降低&#xff0c;比如对于不方便测量的物体使用AR测量&#xff0c;方便又准确&#xff1b;遇到陌生的路段使用AR导航&#xff0c;清楚又便捷&#xff1b;网购时拿不准的物品使用AR购物&#xff0c;体验更…

【每天进步一点点】函数表达式和函数声明

函数声明 function 函数名&#xff08;&#xff09;{} 函数声明会被率先读取。 函数声明后不会立即执行&#xff0c;会在我们需要的时候调用到。 由于函数声明不是一个可执行语句&#xff0c;所以不以分号结束。 函数表达式 表达式赋值给了一个变量 const 变量名 functi…

GT-suite v2016解决许可证过期问题(附新版liscense下载地址)

安装GT-suite v2016时遇到了如图报错的问题。当时的报错找不到了&#xff0c;下图是贴吧相同问题的报错图。 为了解决问题&#xff0c;先根据某网友的如下答复操作&#xff1a; 添加环境变量后仍然有相同报错。 看来需要寻找其他方法。 再尝试着卸载GT-suite v2016&#xff0c…

【Python--torch.nn.functional】F.normalize用法 + 代码说明

【Python–torch.nn.functional】F.normalize介绍 代码说明 文章目录【Python--torch.nn.functional】F.normalize介绍 代码说明1. 介绍2. 代码说明2.1 一维Tensor2.2 二维Tensor2.3 三维Tensor3. 总结1. 介绍 import torch.nn.functional as F F.normalize(input: Tensor, …

(考研湖科大教书匠计算机网络)第四章网络层-第五节:静态路由配置及其可能产生的路由环路问题

获取pdf&#xff1a;密码7281专栏目录首页&#xff1a;【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一&#xff1a;静态路由配置&#xff08;1&#xff09;概述&#xff08;2&#xff09;举例说明A&#xff1a;静态路由配置B&#xff1a;默认路由C&#xff1a;特定…

【Python从入门到进阶】7、运算符

接上篇《6、变量规范及类型转换》 上一篇我们学习了Python变量的命名规范以及类型转换。本篇我们来学习Python的运算符部分&#xff0c;包括算数运算符、赋值运算符、比较运算符、逻辑运算符等。 一、运算符含义 运算符用于执行程序代码运算&#xff0c;会针对一个以上操作数…

网友眼中越老越吃香的行业,果然是风向变了!

越老越吃香的行业&#xff0c;一直都是被热议的话题。对于年轻人来说&#xff0c;找到一个适合自己的并且具有前景的工作&#xff0c;不是一件容易的事情。 最近&#xff0c;看到有人在平台上问相关的问题&#xff0c;本着认真看一看的态度点进去&#xff0c;却差点被热评第一…

MyBatis详解1——相关配置

一、什么是MyBatis 1.定义&#xff1a;是一个优秀的持久层框架&#xff08;ORM框架&#xff09;&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis是一个用来更加简单的操作和读取数据库的工具。 2.支持的操作方式&#xff1a;xml或者注解实现操作&#xff08;xm…