目录
使用Synchronized关键字
使用ReentrantLock
使用Redis分布式锁
使用Actor模型
假设场景:当涉及到多线程环境下的账户转账操作时,需要确保数据一致性和并发安全。以下是使用不同方式实现多线程下账户转账的示例代码:
performTransfer
方法完成实际的转账过程。该方法会捕获转账过程中可能出现的异常,并进行相应的处理和回滚操作,以确保数据一致性。public class Account {
private int balance;
private final int id;
public Account(int id, int balance) {
this.id = id;
this.balance = balance;
}
public synchronized void withdraw(int amount) {
if (amount <= 0 || amount > balance) {
throw new IllegalArgumentException("Invalid withdrawal amount");
}
balance -= amount;
}
public synchronized void deposit(int amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Invalid deposit amount");
}
balance += amount;
}
public int getId() {
return id;
}
public int getBalance() {
return balance;
}
}
public class TransferManager {
public static void transfer(Account from, Account to, int amount) {
if (from.getId() < to.getId()) {
synchronized (from) {
synchronized (to) {
performTransfer(from, to, amount);
}
}
} else if (from.getId() > to.getId()) {
synchronized (to) {
synchronized (from) {
performTransfer(from, to, amount);
}
}
} else {
throw new IllegalArgumentException("Cannot transfer to the same account");
}
}
private static void performTransfer(Account from, Account to, int amount) {
try {
from.withdraw(amount);
to.deposit(amount);
} catch (Exception e) {
// Handle exception and rollback if necessary
// 可根据具体情况,捕获并处理转账过程中可能出现的异常,例如余额不足等
// 如果发生异常,可以进行回滚操作,确保数据一致性
}
}
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Account {
private int balance;
private final int id;
private Lock lock = new ReentrantLock();
public Account(int id, int balance) {
this.id = id;
this.balance = balance;
}
public void withdraw(int amount) {
lock.lock();
try {
balance -= amount;
} finally {
lock.unlock();
}
}
public void deposit(int amount) {
lock.lock();
try {
balance += amount;
} finally {
lock.unlock();
}
}
public int getId() {
return id;
}
public int getBalance() {
return balance;
}
}
public class TransferManager {
public static void transfer(Account from, Account to, int amount) throws InterruptedException {
boolean success = false;
while (!success) {
if (from.lock.tryLock()) {
try {
if (to.lock.tryLock()) {
try {
from.withdraw(amount);
to.deposit(amount);
success = true;
} finally {
to.lock.unlock();
}
}
} finally {
from.lock.unlock();
}
}
// 等待一段时间再尝试获取锁
Thread.sleep(10);
}
}
}
TransferManager
类的transfer
方法中,添加了对获取锁成功与否的判断。如果成功获取锁,则进行转账操作;如果获取锁失败,则可以自行选择如抛出异常或者记录日志等操作。这样可以更好地处理在分布式环境下的锁获取情况。import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
public class RedisDistributedLock {
private final RedisTemplate redisTemplate;
public RedisDistributedLock(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
public boolean acquireLock(String lockKey) {
Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, "", 1, TimeUnit.SECONDS);
return result != null && result;
}
public void releaseLock(String lockKey) {
RedisScript script = new DefaultRedisScript<>("if redis.call('get', KEYS[1]) then return redis.call('del', KEYS[1]) else return 0 end", Long.class);
redisTemplate.execute(script, Collections.singletonList(lockKey));
}
}
public class TransferManager {
private RedisDistributedLock distributedLock;
public TransferManager(RedisDistributedLock distributedLock) {
this.distributedLock = distributedLock;
}
public void transfer(Account from, Account to, int amount) {
String lockKey = "transfer_lock_" + from.getId() + "_" + to.getId();
if (distributedLock.acquireLock(lockKey)) {
try {
from.withdraw(amount);
to.deposit(amount);
} finally {
distributedLock.releaseLock(lockKey);
}
} else {
// 获取锁失败,处理逻辑
// 可以选择抛出异常或者记录日志等操作
}
}
}
TransferActor
继承了线程类,传入TransferMessage
消息对象,然后进行加锁、转账操作等逻辑。TransferManager
则通过线程池来执行转账操作。虽然以上代码实现了多线程下的转账操作,但是如果有大量的并发请求,还是会存在性能问题和死锁问题。因此,建议使用Actor框架,如Akka,来更好地处理这些问题。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Account {
private int balance;
private final int id;
public Account(int id, int balance) {
this.id = id;
this.balance = balance;
}
public void withdraw(int amount) {
balance -= amount;
}
public void deposit(int amount) {
balance += amount;
}
public int getId() {
return id;
}
public int getBalance() {
return balance;
}
}
public class TransferMessage {
private final Account from;
private final Account to;
private final int amount;
public TransferMessage(Account from, Account to, int amount) {
this.from = from;
this.to = to;
this.amount = amount;
}
public Account getFrom() {
return from;
}
public Account getTo() {
return to;
}
public int getAmount() {
return amount;
}
}
public class TransferActor extends Thread {
private final TransferMessage message;
public TransferActor(TransferMessage message) {
this.message = message;
}
@Override
public void run() {
synchronized (message.getFrom()) {
synchronized (message.getTo()) {
if (message.getFrom().getBalance() >= message.getAmount()) {
message.getFrom().withdraw(message.getAmount());
message.getTo().deposit(message.getAmount());
} else {
// 处理余额不足的逻辑
System.out.println("Insufficient balance.");
}
}
}
}
}
public class TransferManager {
private final ExecutorService executorService = Executors.newFixedThreadPool(10);
public void transfer(Account from, Account to, int amount) {
TransferMessage message = new TransferMessage(from, to, amount);
executorService.submit(new TransferActor(message));
}
// 其他代码
}
优化以上代码:
Account
类添加了一个私有锁对象lock
来避免并发访问问题。TransferActor
实现了Runnable
接口而不是直接继承Thread
类,以更好地支持线程池执行。TransferManager
调用execute
方法代替submit
方法,因为我们不需要获取任务的返回结果。这些改进可以提高代码的并发性能和可靠性。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Account {
private int balance;
private final int id;
private final Object lock = new Object();
public Account(int id, int balance) {
this.id = id;
this.balance = balance;
}
public void withdraw(int amount) {
synchronized (lock) {
balance -= amount;
}
}
public void deposit(int amount) {
synchronized (lock) {
balance += amount;
}
}
public int getId() {
return id;
}
public int getBalance() {
return balance;
}
}
public class TransferMessage {
private final Account from;
private final Account to;
private final int amount;
public TransferMessage(Account from, Account to, int amount) {
this.from = from;
this.to = to;
this.amount = amount;
}
public Account getFrom() {
return from;
}
public Account getTo() {
return to;
}
public int getAmount() {
return amount;
}
}
public class TransferActor implements Runnable {
private final TransferMessage message;
public TransferActor(TransferMessage message) {
this.message = message;
}
@Override
public void run() {
synchronized (message.getFrom()) {
synchronized (message.getTo()) {
if (message.getFrom().getBalance() >= message.getAmount()) {
message.getFrom().withdraw(message.getAmount());
message.getTo().deposit(message.getAmount());
} else {
// 处理余额不足的逻辑
System.out.println("Insufficient balance.");
}
}
}
}
}
public class TransferManager {
private final ExecutorService executorService = Executors.newFixedThreadPool(10);
public void transfer(Account from, Account to, int amount) {
TransferMessage message = new TransferMessage(from, to, amount);
executorService.execute(new TransferActor(message));
}
// 其他代码
}
利用Akka框架实现此功能:
AccountActor
的createReceive
方法中,添加了对余额不足的处理逻辑。当进行取款操作时,先判断余额是否足够,如果足够则进行取款操作,否则输出"Insufficient balance."。这样可以更好地处理余额不足的情况。TransferManager
的transfer
方法中,修改了消息的发送者为自身(getSelf()
),以便在AccountActor
中可以区分消息来源。import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
public class AccountActor extends AbstractActor {
private int balance;
@Override
public Receive createReceive() {
return receiveBuilder()
.match(WithdrawMessage.class, msg -> {
if (balance >= msg.getAmount()) {
balance -= msg.getAmount();
} else {
// 处理余额不足的逻辑
System.out.println("Insufficient balance.");
}
})
.match(DepositMessage.class, msg -> {
balance += msg.getAmount();
})
.build();
}
}
public class TransferManager {
private final ActorSystem system = ActorSystem.create("transferSystem");
private final ActorRef accountActor1 = system.actorOf(Props.create(AccountActor.class), "account1");
private final ActorRef accountActor2 = system.actorOf(Props.create(AccountActor.class), "account2");
public void transfer(int amount) {
accountActor1.tell(new WithdrawMessage(amount), getSelf());
accountActor2.tell(new DepositMessage(amount), getSelf());
}
// 其他代码
}