有 Java 编程相关的问题?

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

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

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

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) 个答案

  1. # 1 楼答案

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

    }

  2. # 2 楼答案

    在实例方法上同步时:

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

    这与:

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

    也就是说,您正在获取的监视器是该类的实例。但是您要创建3个单独的实例(每个线程调用^{),并分别获取每个实例上的监视器,因此同步实际上是不可操作的

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

    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实例


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

  3. # 3 楼答案

    我自己提出了一个更好的解决方案。正如@urag所说,我们需要一个对象来调用同步方法,而我在evrytime创建一个新对象,因此调用了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");
        }
    }