有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java中的多线程同步失败

我从the tutorial读到:

it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

然而,在我的简单示例中,仍然存在访问message对象的竞争

public class TestThread extends Thread{
    int thread;
    StringBuilder message;

    public TestThread(int thread, StringBuilder message) {
        this.thread=thread;
        this.message=message;
        start();
    }

    public void run() {
        synchronized(this){
            for (int i=0; i<1000000; i++) {
                double a=2*2;
            }
            modifyMessage();
        }
    }

    public synchronized void modifyMessage() {
        message.append(thread);
    }
}

public class TestMultithreading {
    static TestThread[] testThreads = new TestThread[5];

    public static void main(String args[]) {
        StringBuilder message = new StringBuilder("A");
        for (int i=0;i<5;i++)
            testThreads[i] = new TestThread(i, message);
        for (int i=0;i<5;i++)
            try {
                testThreads[i].join();
            } catch (InterruptedException e) {}
        out.println(message);
    }
}

我希望这将有长度为6的字符串的保证输出。然而,我不时看到这样的情况:

A1034

这意味着其中一个线程修改对象失败。有人能给我解释一下,为什么会发生这种情况,并提出解决问题的办法吗


共 (2) 个答案

  1. # 1 楼答案

    您已经回答了自己的问题:

    When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block

    同步仅阻止对同一对象的方法的访问,这意味着在每个线程中可以同时调用modifyMessage()

    你要找的是一个类似这样的

       for (int i=0; i<1000000; i++) {
           double a=2*2;
       }
       synchronized(message){
           modifyMessage();
       }
    

    现在,该方法是每个StringBuilder实例只调用一次

  2. # 2 楼答案

    您的方法都在另一个对象(this)上同步

    如果将方法更改为在单个对象上同步,它将起作用。例如

    public void modifyMessage() {
        synchronized(message) {
            message.append(thread);
        }
    }