Synchronized Statements作用

本文通过一个银行账户存款示例,展示了在多线程环境下使用同步锁(synchronized)来确保数据一致性和可见性的必要性。当多个线程同时访问并修改同一资源时,如果不采取适当的同步措施,可能会导致数据混乱。

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

先来看下lock的作用

intrinsic Locks and Synchronization

Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.

Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.

When a thread releases an intrinsic lock, a happens-before relationship is established between that action and any subsequent acquistion of the same lock.

我写了一个程序可以体会一下


账户account

package com.yuxuan.j2se;
/*
 * 账户
 */
public class Account {
private Integer price=300;

public void deductPrice(Integer price) {
	this.price = this.price-price;
}

public void addPrice(Integer price) {
	this.price = this.price+price;
}

public Integer getPrice() {
	return price;
}

public void setPrice(Integer price) {
	this.price = price;
}


}

person1

package com.yuxuan.j2se;

public class Person1 implements Runnable{
private Account account;

public Person1(Account account) {
	super();
	this.account = account;
}

@Override
public void run() {
synchronized (account) {
	
	System.out.println("person1原account价格"+account.getPrice());
	account.addPrice(100);
	System.out.println("person1存入100acount后,account价格"+account.getPrice());
	try {
		
		Thread.currentThread().sleep(5000);
		
		System.out.println("person1睡了5秒后,account价格"+account.getPrice());
		
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}

	
	
}

}

Person2

package com.yuxuan.j2se;

public class Person2 implements Runnable{
private Account account;

public Person2(Account account) {
	super();
	this.account = account;
}

@Override
public void run() {
	synchronized (account) {
		
		System.out.println("person2原account价格"+account.getPrice());
		account.addPrice(200);
		System.out.println("person2存入200后,account价格"+account.getPrice());
		try {
			
			Thread.currentThread().sleep(3000);
			System.out.println("person2睡3秒后,accout价格"+account.getPrice());
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	
}

}


person3

package com.yuxuan.j2se;

public class Person3 implements Runnable{
private Account account;

public Person3(Account account) {
	super();
	this.account = account;
}

@Override
public void run() {
	synchronized (account) {
		
		System.out.println("person3原account价格"+account.getPrice());
		account.deductPrice(200);
		System.out.println("person3扣除200后,account价格"+account.getPrice());
		try {
			
			Thread.currentThread().sleep(5000);
			System.out.println("person3睡5秒后,account价格"+account.getPrice());
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	
}

}

Test

package com.yuxuan.j2se;

public class TestAccount {
 public static void main(String[] args) throws InterruptedException {
	Account account =  new Account();
	Thread thread1 = new Thread(new Person1(account));
	Thread thread2 = new Thread(new Person2(account));
	Thread thread3 = new Thread(new Person3(account));
	thread1.start();
	thread2.start();
	thread3.start();

}
}

你会看到像下面的输出

person1原account价格300
person1存入100acount后,account价格400
person1睡了5秒后,account价格400
person3原account价格400
person3扣除200后,account价格200
person3睡5秒后,account价格200
person2原account价格200
person2存入200后,account价格400
person2睡3秒后,accout价格400

上面没有看到什么不对的地方


而如果把Person1,person2,person3里面的

synchronized (account) {
}
去掉,改成如

public void run() {
	
		
		System.out.println("person3原account价格"+account.getPrice());
		account.deductPrice(200);
		System.out.println("person3扣除200后,account价格"+account.getPrice());
		try {
			
			Thread.currentThread().sleep(5000);
			System.out.println("person3睡5秒后,account价格"+account.getPrice());
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	


你会看到像下面的输出,

person1原account价格300
person3原account价格300
person2原account价格300
person3扣除200后,account价格200
person1存入100acount后,account价格400
person2存入200后,account价格400
person2睡3秒后,accout价格400
person1睡了5秒后,account价格400
person3睡5秒后,account价格400

person3绝对很乐意这样做,300块,取出了200块,还剩200!这就是应为没加synchronized (account) {}

导致钱显示的不正确


### Java 多线程环境下事务控制的方法 在多线程环境中,确保数据的一致性和完整性至关重要。Java 提供了几种机制来实现这一点。 #### 使用 `synchronized` 关键字 `synchronized` 是最常用的同步手段之一。它可以用来修饰方法或代码块,确保同一时刻只有一个线程能够访问临界区资源[^1]。 ```java public class Counter { private int count; public synchronized void increment() { this.count++; } public synchronized int getCount() { return this.count; } } ``` #### 利用锁对象 (`Lock`) 相比于内置的监视器锁定(`synchronized`),显式的 `Lock` 接口提供了更加灵活的功能集合。它支持公平性策略以及尝试加锁操作等特性[^2]。 ```java import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class BoundedBuffer { final Lock lock = new ReentrantLock(); // ... other methods ... } ``` #### 借助原子变量 (Atomic Variables) 对于简单的计数场景,可以考虑采用 `java.util.concurrent.atomic` 包下提供的原子类,这些类可以在不阻塞的情况下完成更新动作,性能更高[^3]。 ```java import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); public void increment() { while(true){ int value = count.get(); if(count.compareAndSet(value, value + 1)){ break; } } } } ``` #### 数据库层面的事务管理 当涉及到数据库交互时,则应依赖于 JDBC 或者 ORM 框架所提供的声明式/编程式事务管理功能[^4]。 ```java Connection conn = null; try{ conn = dataSource.getConnection(); conn.setAutoCommit(false); // execute SQL statements here... conn.commit(); }catch(Exception ex){ if(conn != null) conn.rollback(); }finally{ if(conn != null && !conn.isClosed()) conn.close(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值