在运行多线程应用程序时,我很难理解同步方法、对象的概念,也很难理解不这样做的主要问题。
据我所知,synchronize
关键字用于确保一次只有一个线程处理特定对象或进入特定 block 或方法,基本上锁定它并在执行结束时解锁,这样其他线程就可以进入它。
但我真的不明白这个问题,我完全困惑,我创建了一个演示应用程序,其中我有 2 个银行帐户,以及一个拥有 5000
资金的银行类和一种方法将特定金额的资金转移到给定帐户,并在其构造函数中创建 2 个银行帐户并启动线程(每个帐户都是一个线程)。
现在,在银行帐户的类中,我有一个 funds
字段,以及线程在启动时调用的 run 方法(继承 Thread 的类),并且 run 方法将循环 10 次,并且通过调用 Bank#takeFunds(int amount)
所以我们开始了,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/