在静态方法和非静态方法上加 Synchronized的区别
https://www.cnblogs.com/aspirant/p/9067916.html
Synchronzied 修饰非静态方法==》对象锁
Synchronzied 修饰静态方法==》其实是类锁,因为是静态方法,它把整个类锁起来了;
1.Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”。
Java中每个对象都有一个锁,并且是唯一的。假设分配的一个对象空间,里面有多个方法,相当于空间里面有多个小房间,如果我们把所有的小房间都加锁,因为这个对象只有一把钥匙,因此同一时间只能有一个人打开一个小房间,然后用完了还回去,再由JVM 去分配下一个获得钥匙的人。
情况1:同一个对象在两个线程中分别访问该对象的两个同步方法
结果:会产生互斥。
解释:因为锁针对的是对象,当对象调用一个synchronized方法时,其他同步方法需要等待其执行结束并释放锁后才能执行。
情况2:不同对象在两个线程中调用同一个同步方法
结果:不会产生互斥。
解释:因为是两个对象,锁针对的是对象,并不是方法,所以可以并发执行,不会互斥。形象的来说就是因为我们每个线程在调用方法的时候都是new 一个对象,那么就会出现两个空间,两把钥匙,
2.Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”。
情况1:用类直接在两个线程中调用两个不同的同步方法
结果:会产生互斥。
解释:因为对静态对象加锁实际上对类(.class)加锁,类对象只有一个,可以理解为任何时候都只有一个空间,里面有N个房间,一把锁,因此房间(同步方法)之间一定是互斥的。
注:上述情况和用单例模式声明一个对象来调用非静态方法的情况是一样的,因为永远就只有这一个对象。所以访问同步方法之间一定是互斥的。
情况2:用一个类的静态对象在两个线程中调用静态方法或非静态方法
结果:会产生互斥。
解释:因为是一个对象调用,同上。
情况3:一个对象在两个线程中分别调用一个静态同步方法和一个非静态同步方法
结果:不会产生互斥。
解释:因为虽然是一个对象调用,但是两个方法的锁类型不同,调用的静态方法实际上是类对象在调用,即这两个方法产生的并不是同一个对象锁,因此不会互斥,会并发执行。
测试代码:
同步方法类:SynchronizedTest.java
public class SynchronizedTest {
/*private SynchronizedTest(){}
private static SynchronizedTest st; //懒汉式单例模式,线程不安全,需要加synchronized同步
public static SynchronizedTest getInstance(){
if(st == null){
st = new SynchronizedTest();
}
return st;
}*/
/*private SynchronizedTest(){}
private static final SynchronizedTest st = new SynchronizedTest(); //饿汉式单利模式,天生线程安全
public static SynchronizedTest getInstance(){
return st;
}*/
public static SynchronizedTest staticIn = new SynchronizedTest(); //静态对象
public synchronized void method1(){ //非静态方法1
for(int i = 0;i < 10;i++){
System.out.println("method1 is running!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public synchronized void method2(){ //非静态方法2
for( int i = 0; i < 10 ; i++){
System.out.println("method2 is running!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public synchronized static void staticMethod1(){ //静态方法1
for( int i = 0; i < 10 ; i++){
System.out.println("static method1 is running!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public synchronized static void staticMethod2(){ //静态方法2
for( int i = 0; i < 10 ; i++){
System.out.println("static method2 is running!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
线程类1:Thread1.java(释放不同的注释可以测试不同的情况)
public class Thread1 implements Runnable{
@Override
public void run() {
// SynchronizedTest s = SynchronizedTest.getInstance();
// s.method1();
// SynchronizedTest s1 = new SynchronizedTest();
// s1.method1();
SynchronizedTest.staticIn.method1();
// SynchronizedTest.staticMethod1();
// SynchronizedTest.staticMethod2();
}
}
线程类2:Thread2.Java
public class Thread2 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
// SynchronizedTest s = SynchronizedTest.getInstance();
// SynchronizedTest s2 = new SynchronizedTest();
// s2.method1();
// s.method2();
// SynchronizedTest.staticMethod1();
// SynchronizedTest.staticMethod2();
// SynchronizedTest.staticIn.method2();
SynchronizedTest.staticIn.staticMethod1();
}
}
主类:ThreadMain.java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadMain {
public static void main(String[] args) {
Thread t1 = new Thread(new Thread1());
Thread t2 = new Thread(new Thread2());
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(t1);
exec.execute(t2);
exec.shutdown();
}
}
总结:
1.对象锁钥匙只能有一把才能互斥,才能保证共享变量的唯一性
2.在静态方法上的锁,和 实例方法上的锁,默认不是同样的,如果同步需要制定两把锁一样。
3.关于同一个类的方法上的锁,来自于调用该方法的对象,如果调用该方法的对象是相同的,那么锁必然相同,否则就不相同。比如 new A().x() 和 new A().x(),对象不同,锁不同,如果A的单利的,就能互斥。
4.静态方法加锁,能和所有其他静态方法加锁的 进行互斥
5.静态方法加锁,和xx.class 锁效果一样,直接属于类的
原文地址:https://www.cnblogs.com/xiang--liu/p/11598981.html
- ASP.NET MVC是如何运行的[2]: URL路由
- 一个简单的小程序演示Unity的三种依赖注入方式
- 在Entity Framework中使用存储过程(三):逻辑删除的实现与自增长列值返回
- 在Entity Framework中使用存储过程(四):如何为Delete存储过程参数赋上Current值?
- ASP.NET MVC是如何运行的(4): Action的执行
- ASP.NET MVC是如何运行的[1]: 建立在“伪”MVC框架上的Web应用
- 在Entity Framework中使用存储过程(五):如何通过存储过程维护多对多关系?
- ASP.NET MVC下基于异常处理的完整解决方案
- 不到40行代码构建正则表达式引擎
- 随便写一篇文章
- Java 10新特性解密
- Android组件化框架项目详解
- ScheduledThreadPoolExecutor原理探究
- TensorFlow下载与安装
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- [漫谈] 状态
- 变量覆盖
- 【Rust日报】2020-08-27 在Arduino Uno上面跑 Rust 程序
- 浅谈类加载
- Rust FFI 编程 - Rust导出共享库06
- go语言文件操作汇总
- Redis 主从复制 哨兵模式实战
- 【Rust日报】2020-08-28 Rust 1.46稳定版发布
- go语言反射
- 和同事谈谈Flood Fill 算法
- 【每周一库】 img_hash,rust下的pHash算法库
- 【Rust日报】2020-08-29 生产环境 Rust 序列化库的选择
- 【投稿】刀哥:Rust学习笔记 5
- Python测试开发django3.视图和URL配置
- 【Rust日报】2020-08-31 easy_rust 正式完成了