【多线程】synchronized同步代码块

2023-11-01

一、前言

       使用synchronized声明的方法在 某些情况下是有弊端的,比如A线程调用同步的方法执行一个长时间的任务,那么B线程就必须等待比较长的时间才能执行,这种情况可以使用synchronized代码块去优化代码执行时间,也就是通常所说的减少锁的粒度

/**
 * 使用synchronized代码块减小锁的粒度,提高性能
 * @author alienware
 *
 */
public class Optimize {

	public void doLongTimeTask(){
		try {
			
			System.out.println("当前线程开始:" + Thread.currentThread().getName() + 
					", 正在执行一个较长时间的业务操作,其内容不需要同步");
			Thread.sleep(2000);
			
			synchronized(this){
				System.out.println("当前线程:" + Thread.currentThread().getName() + 
					", 执行同步代码块,对其同步变量进行操作");
				Thread.sleep(1000);
			}
			System.out.println("当前线程结束:" + Thread.currentThread().getName() +
					", 执行完毕");
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		final Optimize otz = new Optimize();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				otz.doLongTimeTask();
			}
		},"t1");
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				otz.doLongTimeTask();
			}
		},"t2");
		t1.start();
		t2.start();
		
	}
	
	
}

       当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一段时间内只能有一个线程被执行,另一个线程必须等待当前线程执行完这个同步代码块以后才能执行该代码块。当一个线程访问object的一个synchronized同步代码块时,另一个线程仍然可以访问该object对象中的非synchronized(this)同步代码块。

二、将任意对象作为对象监视器

       多个线程调用同一个对象中的不同名称的synchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的,阻塞的

       这说明synchronized同步方法或synchronized(this)  同步代码块分别有两种作用。

      (1)synchronized同步方法

       ①对其他synchronized同步方法或synchronized(this)同步代码块呈阻塞状态

       ②同一时间只有一个线程可以执行synchronized同步方法中的代码

       (2)synchronized(this)同步代码块

       ①对其他synchronized同步方法或synchronized(this)同步代码块呈阻塞状态

       ②同一时间只有一个线程可以执行synchronized(this)同步代码块中的代码。

       在前面的学习中,使用synchronized(this)格式来同步代码块,其实Java还支持对“任意对象”作为“对象监视器”来实现同步的功能。这个“任意对象”大多数是实例变量及方法的参数,使用格式为synchronized(非this对象)。

     service类:

//Java还支持对任意对象作为对象监视器来实现同步功能,非this对象
public class service {
	private String usernameParam;
	private String passwordParam;
	private String anyString= new String();
	
	public void setUsernamePassword(String username,String password){
		try {
			synchronized (anyString) {
				System.out.println("线程名称为: "+Thread.currentThread().getName()+"在 "+System.currentTimeMillis()+" 进入同步代码块");
				usernameParam=username;
				Thread.sleep(3000);
				passwordParam=password;
				System.out.println("线程名称为: "+Thread.currentThread().getName()+"在 "+System.currentTimeMillis()+" 离开同步代码块");
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	
}
     ThreadA:

package synchronizedCodeblock.mytask;

public class ThreadA extends Thread {

	private service service;
	public ThreadA(service service){
		super();
		this.service=service;
	}
	@Override
	public void run(){
		service.setUsernamePassword("a", "aa");
	}
}
    ThreadB

    

package synchronizedCodeblock.mytask;

public class ThreadB extends Thread {

	private service service;
	public ThreadB(service service){
		super();
		this.service=service;
	}
	@Override
	public void run(){
		service.setUsernamePassword("b", "bb");
	}
}
     RunTest

package synchronizedCodeblock.mytask;

public class RunTest {

	public static void main(String[] args) {
		service service =new service();
		ThreadA a= new ThreadA(service);
		a.setName("A");
		a.start();
		ThreadB b=new ThreadB(service);
		b.setName("B");
		b.start();
	}
} 
     最终实现了同步效果,输出结果如下:


       锁非this对象具有一定的优点:如果一个类中有很多个synchronized方法,这时虽然能实现同步,但会受到阻塞,所以影响消息;但如果使用同步代码块锁非this对象,则synchronized(非this)代码块的程序与同步方法是异步的。不与其他锁this同步方法争抢this锁,则可以大大提高运行效率。

将service代码更改如下:

package synchronizedCodeblock.mytask;

//Java还支持对任意对象作为对象监视器来实现同步功能,非this对象
public class service {
	private String usernameParam;
	private String passwordParam;
	//private String anyString= new String();
	
	public void setUsernamePassword(String username,String password){
		try {
			String anyString= new String();
			synchronized (anyString) {
				System.out.println("线程名称为: "+Thread.currentThread().getName()+"在 "+System.currentTimeMillis()+" 进入同步代码块");
				usernameParam=username;
				Thread.sleep(3000);
				passwordParam=password;
				System.out.println("线程名称为: "+Thread.currentThread().getName()+"在 "+System.currentTimeMillis()+" 离开同步代码块");
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	
} 
最终输出结果:不是同步的而是异步的(因为不是同一个锁,new String()作为对象监视器)如下图所示


      使用synchronized(非this对象x)同步代码块 进行同步操作时,对象监视器必须是同一个对象。如果不是同一个对象监视器,运行的结果就是异步调用了,就会交叉运行。



      









本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【多线程】synchronized同步代码块 的相关文章

  • 多线程与高并发编程进阶(二)

    前言 前文多线程与高并发入门中 已经介绍了多线程编程的目的以及实际应用中可能会遇到的问题 本文接着叙述关于多线程并发机制的底层原理 volatile以及synchronized 一般来说 Java代码从编写到最后的执行会经历以下的过程 Ja
  • 多线程学习----join()的用法

    join的用法一 join 方法可以使得一个线程在另一个线程结束后再执行 如果join 方法在一个线程实例上调用 当前运行着的线程将阻塞直到这个线程实例完成了执行 首先来看个例子 author QingHe Creation on 2005
  • 线程中捕获异常

    总结 正常线程抛出异常时 在外部是捕捉不到的 当此类异常跑抛出时 线程就会终结 而对于主线程和其他线程完全不受影响 且完全感知不到某个线程抛出的异常 也是说完全无法catch到这个异常 解决方案 为线程添加未捕获异常处理器 Uncaught
  • 【JAVA多线程11】线程基本方法-线程等待(wait)/线程唤醒(notify)

    1 wait notify notifyAll 方法是Object的本地final方法 无法被重写 2 wait 使当前线程阻塞 前提是 必须先获得锁 一般配合synchronized 关键字使用 即 一般在synchronized 同步代
  • 可重入锁(ReentrantLock和synchronized原理及区别)+锁升级

    目录 1 Synchronized底层原理 ReentrantLock实现的原理及使用 Java中synchronized 和 ReentrantLock 有什么不同 追问3 synchronized锁升级的过程说一下 追问4 synchr
  • JAVA高并发---收藏的好文章(持续更新)

    JAVA高并发 AQS详解 转载 学习前因 本来对多线程略懂 最近忽然看到了CountDownLatch 的用法 忽然想简单看看它的原理 了解一下它阻塞线程的方法 我只知道阻塞线程的lock 和wait notifyAll 才发现原来还有L
  • Java技术之AQS详解

    AbstractQueuedSynchronizer 简写为AQS 抽象队列同步器 它是一个用于构建锁和同步器的框架 许多同步器都可以通过AQS很容易并且高效的构造出来 以下都是通过AQS构造出来的 ReentrantLock Reentr
  • Java 多线程事务回滚 ——多线程插入数据库时事务控制

    背景 日常项目中 经常会出现一个场景 同时批量插入数据库数据 由于逻辑复杂或者其它原因 我们无法使用sql进行批量插入 串行效率低 耗时长 为了提高效率 这个时候我们首先想到多线程并发插入 但是如何控制事务呢 直接上干货 实现效果 开启多条
  • 深入研究java.lang.ThreadLocal类

    深入研究java lang ThreadLocal类 一 概述 ThreadLocal是什么呢 其实ThreadLocal并非是一个线程的本地实现版本 它并不是一个Thread 而是threadlocalvariable 线程局部变量 也许
  • UncaughtExceptionHandler异常处理机制

    解释 UncaughtExceptionHandler类是java1 5里新增的 Thread类里面的一个函数式接口类的 类名意思为 未捕获的异常处理 该类的注释接口意思 接口处理器时调用线程突然终止 由于未捕获到异常 当一个线程要终止由于
  • 【2021最新版】Java多线程&并发面试题总结(108道题含答案解析)

    文章目录 JAVA并发知识库 1 Java中实现多线程有几种方法 2 继承Thread类 3 实现Runnable接口 4 ExecutorService Callable Future有返回值线程 5 基于线程池的方式 6 4 种线程池
  • Java并发总结之Java内存模型

    本文主要参考 深入理解Java虚拟机 和 Java并发编程的艺术 对Java内存模型进行简单总结 一 CPU和缓存一致性 1 CPU高速缓存 为了解决CPU处理速度和内存处理速度不对等的问题 就是在CPU和内存之间增加高速缓存 当程序在运行
  • java线程池的使用

    线程池概述 线程池 Thread Pool 是一种基于池化思想管理线程的工具 使用线程池可以带来诸多好处 降低资源消耗 通过池化技术复用已创建的线程 减少线程创建和销毁的损耗 提高响应速度 任务到达时 特定情况下无需再创建线程 便于管理 j
  • Java线程中 suspend() 和 resume() 、wait() 和 notify()、park和unpark

    suspend 和 resume 方法 两个方法配套使用 suspend 使得线程进入阻塞状态 并且不会自动恢复 必须其对应的 resume 被调用 才能使得线程重新进入可执行状态 但suspend 方法阻塞时都不会释放占用的锁 很容易引起
  • Java多线程 - 线程状态

    线程状态 五个状态 新生 就绪 运行 死亡 阻塞 停止线程 不推荐使用JDK提供的stop destroy 方法 已弃用 推荐线程自己停止 建议用一个标志位进行终止变量 到flag false 则终止线程运行 public class St
  • Java并发编程:并发容器之CopyOnWriteArrayList(转载)

    http www cnblogs com dolphin0520 p 3938914 html 原文链接 http ifeve com java copy on write Copy On Write简称COW 是一种用于程序设计中的优化策
  • 【多线程】线程安全、锁的同步和异步

    一 基本概念 线程安全 当多个线程访问某一个类 对象或方法 时 这个类始终都能表现出正确的行为 那么这个类 对象或方法 就是线程安全的 非线程安全 非线程主要是指多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改 值不同步的情况
  • java定时器Timer的使用

    在JDK库中Timer类主要负责计划任务的功能 也就是在指定的时间开始执行某一个任务 Timer类的主要作用就是设置计划任务 但是封装任务的类的是TimerTask类 下面展示几个例子 在指定的日期执行一次某一任务 import java
  • 多线程事务的实现

    为了提高效率 在批量执行SQL时 可以采用多线程并发执行的方式 每个线程在执行完SQL后 暂时不提交事务 而是等待所有线程的SQL执行成功后 一起进行提交 如果其中任何一个线程执行失败 则所有线程都会回滚 一 springboot多线程 声
  • 多线程案例:银行取钱

    不安全取钱 两个人去银行取钱 账户 银行取钱 给账户上锁 public class UnsafeBank public static void main String args 账户 Account3 account new Account

随机推荐

  • 春秋云镜 CVE-2022-24112

    春秋云镜 CVE 2022 24112 Apache APISIX batch requests SSRF RCE 漏洞 靶标介绍 Apache Apisix是美国阿帕奇 Apache 基金会的一个云原生的微服务API网关服务 该软件基于O
  • opencv 轮廓放大_使用OpenCV和Python构建自己的车辆检测模型

    概述 你对智慧城市领域有兴趣吗 如果是的话 你会喜欢这个关于实现你自己的车辆检测系统的教程 在深入实现部分之前 我们将首先了解如何检测视频中的移动目标 我们将使用OpenCV和Python构建自动车辆检测器 介绍 关于智慧城市的理念 以及自
  • 三分钟了解腾讯云DDOS基础防护

    三分钟了解腾讯云DDOS基础防护 DDoS 基础防护应用场景包括哪些 腾讯云 DDoS 基础防护应用于攻击频率不高且攻击峰值不超过基础防护阈值的 DDoS 攻击防护场景 当攻击流量超过一定流量时 将自动启动 DDoS 清洗设备进行流量清洗
  • nettty

    https www jianshu com p e58674eb4c7a 1 Netty 异步和事件驱动 1 Netty 能够帮助搭建允许系统能够扩展到支持150000名并发用户 2 Netty 设计关键 异步 事件驱动 1 1 Java网
  • Linux下JDK1.8安装及配置

    进入Linux系统Ubuntu debian或centos安装JDK1 8并配置环境变量 通过终端在 opt目录下新建base文件夹 命令行 sudo mkdir opt base 然后进入java目录 命令行 cd opt base 到官
  • Ubuntu安装Nvidia显卡驱动

    原来没那么复杂 https linuxconfig org how to install the nvidia drivers on ubuntu 18 04 bionic beaver linux 我用的第一种方法 安装途中遇到了一个 v
  • php ajax右边悬浮购物车,一个简单的php+Ajax购物车程序代码(1/2)_PHP教程

    cart name name this gt items SESSION this gt cart name setItemQuantity Set the quantity of an item param string order co
  • 远程服务器docker配置并启动jupyter lab

    前提摘要 在远程服务器docker中存在镜像 但想通过jupyter lab来更好的可视化代码结果 首先登录远程服务器ssh 并拉取镜像 p是端口映射 22给ssh连接 jupyter lab的默认端口是8889 8888是自己的端口号 n
  • Ubuntu下OpenResty 搭建高性能服务端

    Socke 介绍 Linux Socket 编程领域为了处理大量连接请求场景 需要使用非阻塞 I O 和复用 select poll epoll 是 Linux API 提供的 I O 复用方式 自从 Linux2 6 中加入了 epoll
  • 函数式,F#都做了哪些优化?

    非函数式语言中使用函数式风格的缺点 函数式的优点 想必大家都已经非常了解了 我们来看看 一般语言使用函数式风格可能带来的问题 变量默认是可变的 为了实现不可变性 开发者只能人为的规范不去改变变量的值 没有明确的变量修改提示 容易因失误改变变
  • 手撸软件测试框架——lua版(四)

    本文简单介绍一下开发测试用例用到的几个关键接口 1 断言 在测试用例中少不了对结果进行校验 校验的方法一般称为断言 assert 也就是说 在进行一系列的操作之后 断定会出现某个确定性的结果 如果这个确定性的结果如期出现 则断言成功 被测试
  • spring读取resources文件夹下的文件报错:cannot be resolved to absolute file path because it dose not reside in th

    spring springboot读取resources文件夹下的文件报错 cannot be resolved to absolute file path because it dose not reside in the file sy
  • k8s之存储、SC、STS、DS篇(一些常见的存储方案)

    为什么要做持久化存储 在k8s中部署的应用都是以pod容器的形式运行的 假如我们部署MySQL Redis等数据库 需要对这些数据库产生的数据做备份 因为Pod是有生命周期的 如果pod不挂载数据卷 那pod被删除或重启后这些数据会随之消失
  • 关于 最新版idea(2021.3.3) 在配置XML文件时候,因为没有加上 .xml变成了文档模式的解决方式

    关于 最新版idea 2021 3 3 在配置XML文件时候 因为没有加上 xml变成了文档模式的解决方式 首先就是关于自己的这个问题 自己到各大论坛上面找了半天 发现更多的都是旧版的 而且上面解决方式根本在新版的idea中根本不能用 最后
  • Hbase分布式集群搭建

    环境准备 hbase软件包 http mirror bit edu cn apache hbase 1 3 1 hbase 1 3 1 bin tar gz 完成hadoop集群环境搭建 安装hbase 首先在hadoop master安装
  • 门函数卷积_卷积及其应用

    卷积公式的由来 卷积公式最开始来自于古典概型 如题 掷两次公平的骰子 点数之和等于8的概率 设随机变量 为第一次掷得的点数 随机变量 为第二次掷得的点数 因此不考虑点数之和等于8的条件 则有 种样本空间 根据条件 相当于给随机变量的取值限定
  • 视觉SLAM十四讲 读书编程笔记 Chapter6 非线性优化

    Chapter6 非线性优化 实践 Ceres 1 安装Ceres依赖库 2 编译安装Ceres 3 曲线拟合问题描述 4 ceres使用方法 5 完整代码 实践 g2o 1 安装g2o依赖库 2 编译安装g2o 3 g2o使用方法 4 完
  • 正确配置并且测试HttpListener的方法(httpcfg的使用)

    在此我列出一些我个人遇到的问题和注意点 具体步骤可以参考后面的参考链接 1 用HttpListener写一个简单的http server 2 使用makecert创建服务器端的认证证书 makecert包含在Windows SDK 中 co
  • 我的世界java版高效率刷怪塔_我的世界超高效率刷怪塔制作教程 砍怪砍到手抽筋...

    刷怪塔能让我们的游戏变的非常的简单 因为无限的经验和物品让我们的游戏变的很爽 今天游戏园小编就为大家分享一个刷怪塔的制作教程 希望大家能够喜欢 做刷怪塔之前先来了解一下游戏刷怪的原理 网上很多人说 刷怪原里是 以玩家为中心 42米以外到72
  • 【多线程】synchronized同步代码块

    一 前言 使用synchronized声明的方法在 某些情况下是有弊端的 比如A线程调用同步的方法执行一个长时间的任务 那么B线程就必须等待比较长的时间才能执行 这种情况可以使用synchronized代码块去优化代码执行时间 也就是通常所