【问题标题】:Synchronisation block does not work correctly同步块无法正常工作
【发布时间】:2018-07-16 07:37:22
【问题描述】:

我正在尝试运行以下代码,但无法获得正确的输出。

预期输出 "欢迎新程序员"

实际输出 “新欢迎程序员”

class First {
    public synchronized void display(String msg) {
        System.out.print("["+msg);
        System.out.println("]");
    }
}

class Second {
    String msg;
    First fobj;
    Second (First fp,String str) {
        fobj = fp;
        msg = str;
        start();
    }

    public void run() {
        synchronized(fobj) {       //Synchronized block
            fobj.display(msg);
        }
    }
}

public class SyncroBlock {
    public static void main (String[] args) {
        First fnew = new First();
        Second ss = new Second(fnew, "welcome");
        Second ss1 = new Second(fnew,"new");
        Second ss2 = new Second(fnew, "programmer");
    }
}

我在哪里做错了? 有人可以纠正我吗?

【问题讨论】:

  • 你这里没有做多线程,所以问题与synchronized无关。如果您删除 synchronized 关键字/包装器,它将打印相同的内容。 - 或者您是否忘记了代码中的某些内容? Second 类中没有 start() 方法,所以这甚至不会编译。
  • @Jesper,他在做,只是错过了示例中的extends Thread
  • 除了上面的注释:你的Second构造函数正在调用缺少的方法start();。您是否不小心删除了重要细节?
  • 第二类stackoverflow.com/users/135589/jesper中已经定义了启动方法
  • 请注意,synchronized 块是多余的,因为您创建了 display() 方法 synchronized

标签: java multithreading synchronisation


【解决方案1】:
  1. 从构造函数启动线程是个坏主意。它违反了安全施工的原则。

    在构造过程中让 this 引用逃逸的一个常见错误是从构造函数启动线程。当一个对象从其构造函数创建一个线程时,它几乎总是与新线程共享其 this 引用,无论是显式(通过将其传递给构造函数)还是隐式(因为 ThreadRunnable 是拥有对象)。然后,新线程可能能够看到拥有的对象在它完全构造之前

    在构造函数中创建线程没有错,但最好不要立即启动线程。相反,公开一个启动拥有线程的startinitialize 方法。从构造函数调用可覆盖的实例方法(既不是private 也不是final)也可以允许this 引用转义。

    3.2.1 安全构造实践,Java Concurrency in Practice by Brian Goetz

  2. Thread#start() 调用可能需要一些时间,因此预期的"welcome -> "new" -> "programmer" 实际上可以以任何顺序

要按照您的计划进行,我们需要确保之前的 run() 已开始执行,然后您才能转到下一个。对于我的机器,在两次调用之间休眠100L 足以获得正确的顺序。

Second ss = new Second(fnew, "welcome");
Thread.sleep(100L);
Second ss1 = new Second(fnew,"new");
Thread.sleep(100L);
Second ss2 = new Second(fnew, "programmer");

这不是一个好的技术,你不应该这样使用它。它使执行顺序化——我们不会从多线程中获得任何好处。

【讨论】:

  • @JaySuthar,如果你觉得它有用,你可以接受这个答案
【解决方案2】:

我认为您忘记实现 Callable 或 Runnable 或您的 Second class 所需的任何内容。

【讨论】:

  • 错了,CallableRunnable 都没有 start() 方法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-08
  • 1970-01-01
  • 1970-01-01
  • 2018-06-15
  • 1970-01-01
  • 2020-09-27
  • 1970-01-01
相关资源
最近更新 更多