【问题标题】:how to achieve synchronization of threads using synchronized method in java?如何在java中使用同步方法实现线程同步?
【发布时间】:2017-12-08 17:15:12
【问题描述】:

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

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]

【问题讨论】:

  • 线程执行顺序未知。由于您在野外启动 3 个线程,它们可以以任意顺序启动
  • 编辑问题以包含您实际看到的输出以及您希望看到的内容可能对您有所帮助。
  • @DaveyDaveDave 它一直都在那里,只是隐藏在代码块中。已编辑。
  • 请注意,即使同步正确,您也不一定会看到该输出。你可能会看到[World] [Hello] [Synchronized]
  • 另外:不要在构造函数中启动线程。这使得在其他情况下无法使用Runnable,例如提交给ExecutorService。请致电new Thread(new SyncMethod(...)).start();

标签: java


【解决方案1】:

我自己提出了一个更好的解决方案。正如@urag 所说,我们需要一个对象来调用同步方法,而我每次创建一个新对象时都会调用 3 个同步方法。我们可以将 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");
    }
}

【讨论】:

    【解决方案2】:

    在这里,您每次调用 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);
    }
    

    }

    【讨论】:

    • 这很有帮助。谢谢你:)
    • 那为什么不把 ABC 的对象设为静态,这会使代码更短;)。检查我的答案。
    • 是的,它会给出相同的结果,所以对于这个特定的例子,它很好,但不要轻易使用静态,它并不总是最好的方法这里是一个很好的链接,讨论静态stackoverflow.com/questions/2671496/…跨度>
    【解决方案3】:

    在实例方法上同步时:

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

    这与:

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

    即您要获取的监视器是该类的 instance。但是您正在创建 3 个单独的实例(每个线程调用 new ABC()),并分别获取每个实例的监视器,因此同步实际上是无操作的。

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

    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 的相同实例传递给所有线程,而不是像urag points out in his/her answer 那样这样做,而不是在每个SyncMethod 中创建一个新实例。有时,当我写答案时,最简单的解决方案就会逃跑;)

    【讨论】:

    • 将相同的锁传递给所有 ABC 实例这样做而不是使用静态对象变量有什么好处?
    • @ScaryWombat 假设您有四个ABC 实例,它们成对工作,因为您关心ab 是否同步; cd 正在同步;但是您不在乎 ac 是否存在。如果您使用的是静态变量,则会在所有 4 个变量中同步,这可能会导致不必要的争用。
    • 感谢您的解释-从现在开始采用
    • @ScaryWombat(这是可变全局状态的一般问题示例)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 2013-06-18
    • 2018-09-18
    • 1970-01-01
    • 2023-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多