如何在java中使用synchronized方法实现线程的同步?

如何在java中使用synchronized方法实现线程的同步?,java,Java,我无法在这里实现线程的同步。我使用了同步方法“meth”她。所以根据定义,一次只能有一个线程进入并打印我想要的输出。但这并没有发生。我需要帮助。多谢各位 class ABC { synchronized public void meth(String msg) { System.out.print("[" + msg); try { Thread.sleep(1000); } catch (InterruptedE

我无法在这里实现线程的同步。我使用了同步方法“meth”她。所以根据定义,一次只能有一个线程进入并打印我想要的输出。但这并没有发生。我需要帮助。多谢各位

class ABC {

    synchronized public void meth(String msg) {
        System.out.print("[" + msg);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + " Thread Interrupted");
        }
        System.out.println("]");
    }
}

class SyncMethod implements Runnable {

    ABC a = new ABC();
    Thread t;

    SyncMethod(String s) {
        t = new Thread(this, s);
        t.start();
    }

    public void run() {
        a.meth(t.getName());
    }

    public static void main(String args[]) {
        new SyncMethod("Hello");
        new SyncMethod("Synchronized");
        new SyncMethod("World");
    }
}

电流输出:

        [Hello [Synchronized [World] ] ] ]
期望输出:

        [Hello]
        [Synchronized]
        [World]

在实例方法上同步时:

class ABC
{
    synchronized public void meth(String msg)
    { ... }
}
这与:

class ABC
{
    public void meth(String msg) {
        synchronized (this) { ... }
    }
}
i、 你正在获取的监视器就是该类的实例。但是您要创建3个单独的实例(每个线程调用
newabc()
),并分别获取每个实例上的监视器,因此同步实际上是不可操作的

您需要在公共对象上进行同步。例如:

class ABC
{
    public void meth(String msg) {
        synchronized (ABC.class) { ... }
    }
}

一般来说,在类上进行同步是不明智的,因为程序中任何地方的任何代码都可以获取该监视器,所以您可能会遇到意外的争用

而是传入一个锁对象:

class ABC
{
    private final Object lock;

    ABC(Object lock) { this.lock = lock; }

    public void meth(String msg) {
        synchronized (lock) { ... }
    }
}
并将相同的
lock
传递给所有要同步的
ABC
实例



但是,您可以将相同的
ABC
实例传递给所有线程,而不是在每个
SyncMethod
中创建一个新实例,而不是像这样做。有时候,当我在写答案时,最简单的解决方案就从我的脑海中消失了;)

看这里,每次调用SyncMethod的构造函数时,您都在创建新的ABC实例,因此您有3个由不同线程调用的类的副本,这样它们就不会竞争监视器,所以您需要为所有3个调用使用相同的ABC对象。这里是解决方案

class SyncMethod implements Runnable {
Thread t;
ABC a;

SyncMethod(String s, ABC a) {
    this.a = a;
    t = new Thread(this, s);
    t.start();

}

public void run() {
    a.meth(t.getName());
}

public static void main(String args[]) {
    ABC a = new ABC();
    new SyncMethod("Hello", a);
    new SyncMethod("Synchronized", a);
    new SyncMethod("World", a);
}

}我自己提出了一个更好的解决方案。正如@urag所说,我们需要一个对象来调用synchronized方法,而我在evrytime创建一个新对象,因此调用了3个synchronized方法。我们可以使ABC类的对象成为静态的,因此它不会自我更新,代码也会变得更短。我已经检查了这项工作

    class ABC
{
    synchronized public void meth(String msg)
    {
        System.out.print("[" + msg);
        try
        {
            Thread.sleep(1000);
        }
        catch(InterruptedException e)
        {
            System.out.println(Thread.currentThread().getName() + " Thread Interrupted");
        }
        System.out.println("]");
    }
}
class SyncMethod implements Runnable
{
    static ABC a = new ABC();
    Thread t;
    SyncMethod(String s)
    {
        t= new Thread(this,s);
        t.start();
    }
    public void run()
    {
        a.meth(t.getName());
    }
    public static void main(String args[])
    {
        //ABC a = new ABC();
        new SyncMethod("Hello");
        new SyncMethod("World");
        new SyncMethod("Synchronized");
    }
}

线程的执行顺序未知。由于您在野外启动了3个线程,它们可以以任意顺序启动。编辑您的问题以包括您实际看到的输出以及您希望看到的内容可能会对您有所帮助。@DaveyDaveDave它一直在那里,只是隐藏在代码块中。已编辑。请注意,即使同步正确,您也不一定会看到该输出。您可能会看到
[World][Hello][Synchronized]
。另外:不要在构造函数中启动线程。这使得在其他情况下无法使用
Runnable
,例如提交给
ExecutorService
。调用
新线程(新的SyncMethod(…).start()相反。将相同的锁传递给所有ABC实例,这样做比使用静态对象变量有什么好处?@ScaryWombat假设您有四个
ABC
实例,成对工作,就像您关心
a
b
同步一样;与
c
d
同步;但是你不在乎
a
c
是否正确。如果您使用的是静态变量,那么您可以在所有4个变量之间进行同步,这可能会导致不必要的争用。感谢您的解释-将从现在开始采用on@ScaryWombat(这是可变全局状态的一般问题的一个例子)。这非常有帮助。谢谢:)那么为什么不让ABC的对象成为静态的,这会使代码更短;)。检查我的答案。是的,它会给出相同的结果,所以对于这个特定的例子,它很好,但不要轻易使用静态。这并不总是最好的方法。这里是一个谈论静态的好链接