Java 同步(对象锁定)未按预期工作

Java synchronization(object locking) not working as expected

请考虑以下代码。

import static java.lang.System.out;

public class Task
{
    public Integer k =  new Integer(10) ;

    public Task()
    {
        out.println(k + " constructor of Task : " + Thread.currentThread().getName());
    }
}

import static java.lang.System.out;

public class Executor2 implements Runnable
{
    private Task task;
    public Executor2(Task t)
    {
        out.println("constructor of Executor2 : " + Thread.currentThread().getName());
        task = t;
    }

    @Override
    public void run()
    {
        synchronized(task.k)
        {
            task.k = 88;
            out.println("changed value of task.k to : " + task.k + " " + Thread.currentThread().getName());
            try
            {
                out.println("sleeping");
                Thread.sleep(5000);
            }
            catch (InterruptedException ex)
            {
                ex.printStackTrace(out);
            }
            out.println("done");
        }
    }
}

import static java.lang.System.out;

public class Executor3 implements Runnable
{
    private Task task;
    public Executor3(Task t)
    {
        out.println("constructor of Executor3 : " + Thread.currentThread().getName());
        task = t;
    }

    @Override
    public void run()
    {
        synchronized(task.k)
        {
          task.k = 888;
          out.println("changed value of task.k to : " + task.k + " " + Thread.currentThread().getName());
        }
    }
}
------------------------------------------------------------
public class Main
{
    public static void main(String[] args)
    {
        Task task = new Task();

        Executor2 executor2 = new Executor2(task);
        Thread thread2 = new Thread(executor2);
        thread2.start();

        Executor3 executor3 = new Executor3(task);
        Thread thread3 = new Thread(executor3);
        thread3.start();
    }
}

下面是程序的输出。

10 Task 的构造函数:main
Executor2 的构造函数:main
Executor3 的构造函数:main
将 task.k 的值更改为:88 Thread-0
睡觉
将 task.k 的值更改为:888 Thread-1
完成

这里令人惊讶的是输出行:将 task.k 的值更改为:888 Thread-1 预计不会在输出行之前打印:完成。 为什么 Integer 对象上的锁在睡眠持续时间结束之前就被释放了?

谢谢。

    synchronized(task.k)
    {
      task.k = 888;

更改同步对象会破坏同步点。然后,您尝试在旧对象上保持同步的同时打印新对象。不要替换线程正在同步的对象!

扩展 David Schwartz 所说的:在几乎所有情况下,如果您要写这个:

synchronized (foo) {
    ...
}

那么引用锁对象的变量应该是一个final字段:

class MyClass {

    final Object foo = new Object();
    ...
    void someMethod(...) {
        synchronized (foo) {
            ...
        }
    }
    ...
}

这将防止您以后犯同样的错误。

同意楼上的说法。此外,在使用私有锁时,一个陷阱是不锁定字符串文字——字符串文字是共享资源。

private final String lock = “xx”;

private final String lock = new String(“xxx”);

第二次加锁就可以了