gpt4 book ai didi

Java 线程安全 - 了解同步的需要

转载 作者:行者123 更新时间:2023-12-01 07:05:00 24 4
gpt4 key购买 nike

在运行多线程应用程序时,我很难理解同步方法、对象的概念,也很难理解不这样做的主要问题。

据我所知,synchronize关键字用于确保一次只有一个线程处理特定对象或进入特定 block 或方法,基本上锁定它并在执行结束时解锁,这样其他线程就可以进入它。

但我真的不明白这个问题,我完全困惑,我创建了一个演示应用程序,其中我有 2 个银行帐户,以及一个拥有 5000 资金的银行类和一种方法将特定金额的资金转移到给定帐户,并在其构造函数中创建 2 个银行帐户并启动线程(每个帐户都是一个线程)。

现在,在银行帐户的类中,我有一个 funds 字段,以及线程在启动时调用的 run 方法(继承 Thread 的类),并且 run 方法将循环 10 次,并且通过调用 Bank#takeFunds(int amount)

从主银行提取 20 美元

所以我们开始了,Bank 类:

public class Bank {

private int bankmoney = 5000;

public Bank() {
Client a = new Client(this);
Client b = new Client(this);

a.start();
b.start();
}

public void takeMoney(Client c, int amount) {
if (bankmoney >= amount) {
bankmoney -= amount;
c.addFunds(amount);
}
}

public void print() {
System.out.println("left: " + bankmoney);
}

public static void main(String... args) {
new Bank();
}
}

以及客户端类:

public class Client extends Thread {

private Bank b;
private int funds;
Random r = new Random();
public Client(Bank b) {
this.b = b;
}

public void addFunds(int funds) {
this.funds += funds;
}

public void run() {
for (int i = 0; i < 10; i++) {
b.takeMoney(this, 20);
}
System.out.println(Thread.currentThread().getName() + " : " + funds);
b.print();
}
}

以及我的输出:

Thread-0 : 200
left: 4800
Thread-1 : 200
left: 4600

该程序以每个帐户中的 200 美元结束,银行中还剩下 4600 美元,所以我并没有真正看到问题,我无法演示线程安全问题,我认为这就是我可以的原因'不明白。

我试图得到关于它到底如何工作的最简单的解释,我的代码如何会变成线程安全问题?

谢谢!

示例:

static void transfer(Client c, Client c1, int amount) {
c.addFunds(-amount);
c1.addFunds(amount);
}

public static void main(String... args) {
final Client[] clients = new Client[]{new Client(), new Client()};

ExecutorService s = Executors.newFixedThreadPool(15);
for (int i = 0; i < 15; i++) {
s.submit(new Runnable() {
@Override
public void run() {
transfer(clients[0], clients[1], 200);
}
});
}

s.shutdown();
while(!s.isTerminated()) {
Thread.yield();
}

for (Client c : clients) {
c.printFunds();
}
}

打印:

My funds: 2000
My funds: 8000

最佳答案

首先,线程不是对象。不要为每个客户端分配单独的线程。线程执行工作,对象包含指定必须做什么的代码。

当您调用 Client 对象上的方法时,它们不会“在该客户端的线程上”执行;而是“在该客户端的线程上”执行。它们在调用它们的线程中执行。

为了让线程做一些工作,您需要将其交给一个实现要在其上执行的代码的对象。这就是 ExecutorService 允许您简单完成的事情。

还要记住,锁不会“锁定对象”,并且 synchronized(anObject) 不会自行阻止另一个线程调用 anObject 的方法同时。锁只会阻止其他线程尝试获取相同的锁,直到第一个线程完成操作为止。

关于Java 线程安全 - 了解同步的需要,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27380942/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com