使用正确的同步方式避免数据丢失
Using the correct way to Synchronized to avoid data loss
我正在尝试创建一个多线程的 ATM 系统,以避免提款请求的数据丢失。
我创建了 2 个线程,每个线程都试图从银行余额中提取 1000-5000
钱。
我不希望线程一起工作,我希望它们中的每一个都等待第二个线程完成工作。
当余额为0,或者取款请求高于当前余额时,两个Thread都应该停止取款。
我的问题是我看到线程 1 运行 4 次立即让线程 2 进入,以此类推线程 2,它们似乎没有等待彼此进入动作。
主要:
class Main {
public static void main(String args[]) {
Bank bank = new Bank(100000);
ThreadSync threadSync = new ThreadSync();
Thread client1 = new ClientThread(bank, threadSync,1);
Thread client2 = new ClientThread(bank, threadSync,2);
client1.start();
client2.start();
}
}
银行:
public class Bank {
private int balance;
public Bank(int balance) {
this.balance = balance;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
客户端线程:
public class ClientThread extends Thread {
private Bank bank;
private ThreadSync threadSync;
private int client;
ClientThread(Bank bank, ThreadSync threadSync, int client) {
this.bank = bank;
this.threadSync = threadSync;
this.client = client;
}
@Override
public void run() {
int randomNumber;
while (bank.getBalance() > 0) {
synchronized (threadSync) {
randomNumber = ((int) (Math.random() * (5000 - 1000 + 1)) + 1000);
try {
if (bank.getBalance() - randomNumber >= 0) {
bank.setBalance(bank.getBalance() - randomNumber);
}
System.out.println(client + " - " + bank.getBalance() + " withdrawed - " + randomNumber);
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
线程同步:
public class ThreadSync {
public void send(String msg)
{
System.out.println("Sending\t" + msg );
try
{
Thread.sleep(1000);
}
catch (Exception e)
{
System.out.println("Thread interrupted.");
}
System.out.println("\n" + msg + "Sent");
}
}
谢谢!
不是一个完整的答案,但你应该知道这是一个错误的模式:
while (...trivial test...) {
synchronized(lock) {
...something that takes some time...
}
}
问题是每次循环释放锁时,几乎接下来它所做的就是再次重新锁定它。如果线程 A 进入循环,然后线程 B 随后 尝试 进入,则线程 B 很可能会 starved.
当线程B试图进入synchronized块时,会swapped out(a.k.a.,"blocked","put to sleep" ) 由操作系统。
当线程 A 释放锁时,OS 需要时间再次换回线程 B。同时,线程 A 已经有了 运行ning 的领先优势:它重新锁定锁,重新开始工作,当线程 B 准备 运行 时,已经太晚了。 OS 将再次换出 B,下一次迭代可能会发生同样的事情,下一次,...
诀窍是重新构造您的程序,以便线程永远不需要将锁保持锁定很长一段时间。这听起来可能很矛盾,但有时您可以通过让线程执行 额外的 工作来加速并行计算,前提是额外的工作能够使它们相互避开。
如果您不能重新构建程序,使大部分实际工作发生在关键部分(即“锁定”部分)之外,那么这可能表明您遇到了问题试图解决不太适合多线程解决方案。
我正在尝试创建一个多线程的 ATM 系统,以避免提款请求的数据丢失。
我创建了 2 个线程,每个线程都试图从银行余额中提取 1000-5000
钱。
我不希望线程一起工作,我希望它们中的每一个都等待第二个线程完成工作。 当余额为0,或者取款请求高于当前余额时,两个Thread都应该停止取款。
我的问题是我看到线程 1 运行 4 次立即让线程 2 进入,以此类推线程 2,它们似乎没有等待彼此进入动作。
主要:
class Main {
public static void main(String args[]) {
Bank bank = new Bank(100000);
ThreadSync threadSync = new ThreadSync();
Thread client1 = new ClientThread(bank, threadSync,1);
Thread client2 = new ClientThread(bank, threadSync,2);
client1.start();
client2.start();
}
}
银行:
public class Bank {
private int balance;
public Bank(int balance) {
this.balance = balance;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
客户端线程:
public class ClientThread extends Thread {
private Bank bank;
private ThreadSync threadSync;
private int client;
ClientThread(Bank bank, ThreadSync threadSync, int client) {
this.bank = bank;
this.threadSync = threadSync;
this.client = client;
}
@Override
public void run() {
int randomNumber;
while (bank.getBalance() > 0) {
synchronized (threadSync) {
randomNumber = ((int) (Math.random() * (5000 - 1000 + 1)) + 1000);
try {
if (bank.getBalance() - randomNumber >= 0) {
bank.setBalance(bank.getBalance() - randomNumber);
}
System.out.println(client + " - " + bank.getBalance() + " withdrawed - " + randomNumber);
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
线程同步:
public class ThreadSync {
public void send(String msg)
{
System.out.println("Sending\t" + msg );
try
{
Thread.sleep(1000);
}
catch (Exception e)
{
System.out.println("Thread interrupted.");
}
System.out.println("\n" + msg + "Sent");
}
}
谢谢!
不是一个完整的答案,但你应该知道这是一个错误的模式:
while (...trivial test...) {
synchronized(lock) {
...something that takes some time...
}
}
问题是每次循环释放锁时,几乎接下来它所做的就是再次重新锁定它。如果线程 A 进入循环,然后线程 B 随后 尝试 进入,则线程 B 很可能会 starved.
当线程B试图进入synchronized块时,会swapped out(a.k.a.,"blocked","put to sleep" ) 由操作系统。
当线程 A 释放锁时,OS 需要时间再次换回线程 B。同时,线程 A 已经有了 运行ning 的领先优势:它重新锁定锁,重新开始工作,当线程 B 准备 运行 时,已经太晚了。 OS 将再次换出 B,下一次迭代可能会发生同样的事情,下一次,...
诀窍是重新构造您的程序,以便线程永远不需要将锁保持锁定很长一段时间。这听起来可能很矛盾,但有时您可以通过让线程执行 额外的 工作来加速并行计算,前提是额外的工作能够使它们相互避开。
如果您不能重新构建程序,使大部分实际工作发生在关键部分(即“锁定”部分)之外,那么这可能表明您遇到了问题试图解决不太适合多线程解决方案。