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

标签 java multithreading

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

据我所知,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/

相关文章:

java - 线程重新运行run()方法

javascript - 如何在 HTML 中禁用一种输入类型

java - 正在寻找适用于 android/java 的 CoAP api/库?

java - 为什么在案例 2 : on Java 7? 中相同的值会出现两个不同的答案

Python 线程安全访问不会阻塞或不受控制的队列增长?

java - 多线程基准测试

java - 当线程已经停止时它已经在运行

c++ - Meyers 实现的 Singleton 模式线程安全吗?

java - 在面板中添加一个复杂的图像,在一个自定义的用户界面中周围有按钮

Java:将 Double 对象转换为 float 的更好方法