Synchronized关键字总结 / ACID

本文总结了线程安全的概念,介绍了Java中的`synchronized`关键字在保证线程安全方面的作用,包括对象锁和类锁的区别。还讨论了同步和异步的概念,以及在使用`synchronized`时需要注意的事项。同时,文章提到了数据库事务的ACID特性,即原子性、一致性、隔离性和持久性,并通过案例解释了一致性的含义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程安全概念:

多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。

synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为"互斥区"或"临界区"


执行步骤:

当多线程访问一个对象的run方法时,会以排队的方式进行处理(这里的排队是按照CPU分配的先后顺序而定的,不是代码执行顺序)
一个线程想要执行synchronized修饰的方法里的代码:
1、尝试获得锁
2、如果拿到锁,执行synchronized代码体内容,拿不到锁,这个线程会不断的尝试获取锁,直到拿到为止,而且是多个线程同时去
竞争这把锁(锁竞争问题)


synchronized修饰方法:

被关键字synchronized修饰的方法采用的是对象锁,而不是把一段代码(方法)当做锁,
所以代码中哪个线程先执行synchronized关键字修饰的方法,哪个线程就持有该方法的锁Lock(不同线程调用同一对象的synchronized方法)

同一个对象调用这两个方法的时候能同步,如果是不同的对象,将不能同步

如果想要不同对象同步,那就要加上static,变成类锁


对象锁和类锁:

静态方法static上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类),
所以如果要实现多个对象公共一个锁,得用类锁,在方法和变量前加上static,类变量,类方法

也可以采用代码块的方式:

synchronized(TicketManager.class){ 业务逻辑 }     -->类锁

synchronized(this) { 业务逻辑 }       -->对象锁


public static synchronized method(){业务逻辑}   -->类锁

public synchronized method(){业务逻辑}   -->对象所


同步和异步:

synchronized同步:
同步的概念就是共享,我们要牢牢记住"共享"这俩个字,如果不是共享的资源,就没有必要进行同步。
同步的目的就是为了线程安全,其实对于线程安全来说,需要满足俩个特性:
原子性(同步)
可见性

异步:asynchronized
异步的概念就是独立,相互之间不受到任何制约。就好像我们学习http的时候,在页面发起的Ajax请求,我们还可以继续浏览或操作页面的内容,二者之间没有任何关系。

public class MyObject {

	public synchronized void method1(){
		try {
			System.out.println(Thread.currentThread().getName());
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/** 先不加synchronized */
	public void method2(){
		System.out.println(Thread.currentThread().getName());
	}
	
	public static void main(String[] args) {
		final MyObject mo = new MyObject();
		
		/**
		 * 分析:
		 * t1线程先持有object对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法
		 * t1线程先持有object对象的Lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步
		 */
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				mo.method1();
			}
		},"t1");
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				mo.method2(); //method2不加synchronized,立刻执行,加上,就要等method1释放对象锁
			}
		},"t2");
		
		//如果是对象锁(仅仅一个),那么两个线程调用同一个对象的两个synchronized方法,需要等第一个方法调用完,返回锁对象,才能继续下一个方法的调用(同步)
		t1.start();
		t2.start();
		
	}
}

synchronized总结:

看到类里面有synchronized方法修饰,要想到:

1、既然有synchronized,说明要同步,多个线程访问这个方法要排队,这个方法里面必定牵扯到了公共资源(成员变量)的访问

2、判断是对象锁还是类锁,就看有没有static修饰,static修饰说明是静态资源,也就是类成员。

也可以用代码块synchronized(this){ 业务逻辑 }的方式写.

(代码块的方式可以做到优化,如果一个方法前面比较耗时,但不牵扯公共资源访问,这部分代码就没必要加同步,只用synchronized把需要同步的成员变量操作括起来就可以了):


脏读:

setValue()如果是synchronizedgetValue()就也要加synchronized,也就是我在setValue的时候,不允许别的线程进来getValue这样数据才不会脏读

如果是对象锁,如下:

public synchronized void setValue(String username, String password){
	//xxxx
}

public synchronized void getValue(String username, String password){
	//syso();
}


注意事项:

不能用字符串常量当成锁

public class ChangeLock {

	private String lock = "lock";
	
	private void method(){
		synchronized (lock) {
			try {
				System.out.println("当前线程 : "  + Thread.currentThread().getName() + "开始");
				lock = "change lock";
				Thread.sleep(2000);
				System.out.println("当前线程 : "  + Thread.currentThread().getName() + "结束");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	
	}
}


关系型数据库事务的四个特性:

数据库事务必须具备ACID特性。ACID是

Atomic原子性,Consistency一致性:Isolation隔离性,Durability持久性。

原子性:整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

一致性:在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。

隔离性:(4种隔离级别)两个事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。1.READ_UNCOMMITTED 2.READ_COMMITTED 3.REPEATABLE_READ 4.SERIALIZABLE

持久性:在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。


一致性案例:

9点读取数据,10分钟才获取,一定是获取9点那一时刻的数据,snaptshot(即使中间被dml操作了,数据库会有undo区域,用于回滚),这是会读取undo的数据,而不是dml后的新值


### Spring MVC 中 `synchronized` 关键字的应用效果 在Spring MVC中应用`synchronized`关键字于Controller层存在特定的影响和局限性。由于Spring MVC中的Bean默认采用单例模式,这意味着在整个应用程序生命周期内只有一个实例被创建并共享给所有的HTTP请求[^3]。 对于Controller级别的同步方法而言,在高并发场景下确实会对性能造成负面影响。每当一个线程进入带有`synchronized`修饰符的方法时,其他试图访问同一资源的线程就必须等待当前操作完成才能继续执行。这不仅降低了系统的响应速度,还可能引发不必要的阻塞现象。 然而,值得注意的是每次HTTP请求都会由独立的线程来处理,并不会共用同一个ThreadLocal变量或局部变量;因此通常情况下不需要通过加锁机制防止数据竞争条件的发生。除非是在静态成员变量上进行修改操作才有可能涉及到线程安全问题。 另外需要注意的一点是如果尝试在一个代理对象上调用私有方法,则即使该方法声明为`synchronized`也不会生效,因为只有公共接口可以被AOP框架所拦截并实施增强逻辑[^2]。 综上所述,在大多数实际应用场景里没有必要也不推荐在Controller层面使用`synchronized`关键字来实现线程安全性控制。更合理的做法应该是确保业务逻辑本身具备良好的无状态特性以及利用数据库层面提供的ACID属性保障事务一致性[^4]。 ```java @Controller public class MyController { @RequestMapping("/example") public synchronized String example() { // 不建议这样做 // 处理逻辑... return "viewName"; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值