当前位置: 首页 > ds >正文

java的synchronized 原理及功能

简介:

Java中的synchronized关键字是一种同步机制,用于控制多个线程对共享资源的访问。

原理:

在Java锁有一个内部锁 Intrinsic Lock,也称为监视器锁或管程锁,每个Java对象都有一个关联的监视器锁,隐式锁通常是由编程语言、运行时库或者虚拟机自动管理的,不需要程序员手动调用锁的获取和释放方法,使用较为简便,并且 隐式锁通常会在不需要的时候自动释放,从而减少了由于忘记释放锁而导致的死锁等问题的风险。通过synchronized关键字来获取和释放对象的监视器锁。

使用:

实例方法加锁

使用synchronized修饰方法时,它将锁定整个方法,即使方法中有多个代码块,也只有一个线程可以进入该方法。

public class AccountingSync implements Runnable {//共享资源(临界资源)static int i=0;/*** synchronized 修饰实例方法*/public synchronized void increase(){i++;}@Overridepublic void run() {for(int j=0;j<1000000;j++){increase();}}public static void main(String[] args) throws InterruptedException {AccountingSync instance = new AccountingSync();Thread t1=new Thread(instance);Thread t2=new Thread(instance);t1.start();t2.start();t1.join();t2.join();System.out.println(i);}
}

运行上述代码,打印出了我们预期的结果 2000000,由于 ++ 操作是非线程安全的,所以这一结果表明我们加锁是成功的。 两个线程是通过同一个实例 instance 运行的,所以他们通过这个实例的同一把锁实现了线程的并发安全,而下面的代码就将无法得到预期的结果:

public class AccountingSyncBad implements Runnable {static int i=0;public synchronized void increase(){i++;}@Overridepublic void run() {for(int j=0;j<1000000;j++){increase();}}public static void main(String[] args) throws InterruptedException {//new新实例Thread t1 = new Thread(new AccountingSyncBad());//new新实例Thread t2 = new Thread(new AccountingSyncBad());t1.start();t2.start();//join含义:当前线程A等待thread线程终止之后才能从thread.join()返回t1.join();t2.join();System.out.println(i);}
}

运行结果打印出了 1452317,这是因为两个线程分别运行在两个 new 出来的不同的实例中,这意味着他们有着两个不同的实例对象锁,因此他们各自对 increase 方法加锁是无法实现锁的作用的。

static 方法加锁:

与实例方法不同,static 方法是无法获取到实例对象的 this 引用的,因此对 static 方法加锁,锁定的目标就是 class 对象,所有使用该类的线程都将获取到同一把锁。

public class AccountingSyncBad implements Runnable {static int i=0;public synchronized void increase(){i++;}@Overridepublic void run() {for(int j=0;j<1000000;j++){increase();}}public static void main(String[] args) throws InterruptedException {//new新实例Thread t1 = new Thread(new AccountingSyncBad());//new新实例Thread t2 = new Thread(new AccountingSyncBad());t1.start();t2.start();//join含义:当前线程A等待thread线程终止之后才能从thread.join()返回t1.join();t2.join();System.out.println(i);}
}

此时运行上述代码可以得到预期的加锁效果,虽然我们通过 new 传入不同的实例,但是因为 static 方法上的 synchronized 关键字是通过对 class 对象加锁,两个线程仍然是在竞争同一把锁。

synchronized 同步代码块

编写 synchronized 同步代码块是最灵活的一种加锁方式了,他不仅可以实现上述两种加锁方式的功能,还可以实现更加精细化的加锁控制。 在某些情况下,我们编写的方法体可能比较大,也可能存在一些比较耗时的操作,而需要同步的代码又只有一小部分,如果直接对整个方法进行同步操作,可能会得不偿失,此时我们可以使用同步代码块的方式对需要同步的代码进行包裹,这样就无需对整个方法进行同步操作了。

public class AccountingSync implements Runnable{static AccountingSync instance = new AccountingSync();static int i=0;@Overridepublic void run() {//省略其他耗时操作....//使用同步代码块对变量i进行同步操作,锁对象为instancesynchronized(instance){for(int j=0;j<1000000;j++){i++;}}}public static void main(String[] args) throws InterruptedException {Thread t1=new Thread(instance);Thread t2=new Thread(instance);t1.start();t2.start();t1.join();t2.join();System.out.println(i);}
}

上述代码我们通过对代码执行的一部分加锁,实现了上述对实例方法加锁的相同功能,我们通过对类的 static 成员 instance 加锁,实现并发安全性。 常用的使用方法有对 this 引用加锁和对 class 对象加锁:

//this,当前实例对象锁
synchronized(this){for(int j=0;j<1000000;j++){i++;}
}//class对象锁
synchronized(AccountingSync.class){for(int j=0;j<1000000;j++){i++;}
}

http://www.xdnf.cn/news/8037.html

相关文章:

  • 继DeepSeek之后,又一国产模型迎来突破,或将解答手机端AI的疑惑
  • 教培机构线上线下课程小程序开发:构建数字化教育新生态
  • 模板初阶【C++】
  • 景区导览系统有哪些技术选型?架构设计到真实场景的攻坚指南(一)
  • docker面试题(4)
  • Parasoft为可口可乐赋能: 强化软件开发与质量保证
  • 二叉树的半线性
  • 前端面经-nginx/docker
  • 【C++】vector容器实现
  • pyomo简介及使用指南
  • EXIST与JOIN连表比较
  • Spring Framework 的 spring-core 和 Spring Security 兼容版本
  • 论文篇-1.3.如何整理一篇论文
  • 【leetcode】75.颜色分类
  • leetcode 3356. 零数组变换 II 中等
  • windows安装python环境
  • Supplemental Table 5FAM49B H-SCORE与其他临床特征的关系
  • Win11上安装docker
  • 技术管理专题学习笔记-技术管理中的障碍和应对(2)
  • 【3. 无重复字符的最长子串】
  • 力扣-三数之和
  • 融云 uni-app IMKit 上线,1 天集成,多端畅行
  • 在 Excel xll 自动注册操作 中使用东方仙盟软件2————仙盟创梦IDE
  • 时钟树:概念与编程详解 (铁头山羊)
  • 人工智能小白转型学习指南
  • 对单调栈的理解
  • Spring IOCDI————(2)
  • Linux | tmux | 无法复制粘贴
  • C++类和对象(2)
  • PyTorch学习之:torch.gather是什么?