0

我是一个新手 java 程序员,对下面的代码片段有点困惑。这是否意味着第一个进入的线程将与第三个线程共享锁?希望有人能帮我澄清一下。提前致谢。

public class T_6 extends Thread    {
    static Object o = new Object();
    static int    counter = 0;
    int id;

    public T_6(int id)  {
        this.id = id;
    }

    public void run () {
        if ( counter++ == 1 )    //confused in here.                
            o = new Object();

        synchronized ( o ) { 
            System.err.println( id + " --->" );
            try {
                sleep(1000);
            } catch (  InterruptedException e ) {
                System.err.println("Interrupted!");
            }
            System.err.println( id + " <---" );
        }
    }

    public static void main (String args []) {
        new T_6(1).start();
        new T_6(2).start();
        new T_6(3).start();
    }
}    
4

3 回答 3

2

当您达到 up-count 和 if 时,您将执行典型的 check-then-act 操作。这里的问题是多个线程可以同时来到这里。这意味着他们将拥有counter. 不同的线程可能都有一个 0 本地副本——这意味着它们将计数到 1 并创建新对象——所有这些。但是它们存储在一个静态容器中——它们可能有也可能没有本地副本。简而言之,这里发生的一切都是偶然的。它们最终可能会在同一个对象上同步——但它们可能会尝试在不同的对象上同步,这意味着它们根本不会同步。

你应该看看finalandvolatile关键字。

final意味着一旦指向某处,就无法重新指向引用。这对锁来说是个好主意。如果您将声明更改为

final static Object o = new Object();

您可以保证o不会更改,并且所有同步都将在同一个对象上进行。

volatile表示禁止虚拟机存储变量的线程本地副本。所有的读取和写入都必须在内存中。这意味着所有线程都将看到其他线程所做的写入。

于 2013-08-14T07:33:11.917 回答
1

为了确保多个线程之间的正确同步,所有线程都必须在同一个对象上获取锁,否则将无法实现同步。

看看这部分代码:

 if ( counter++ == 1 )    //confused in here.                
        o = new Object();

这部分对于使代码线程安全根本不是必需的。删除上面引起混淆的代码。您在声明对象时已经创建了该对象的实例。现在为了确保所有线程之间的线程安全,让它们在您已经创建的同一个对象上获取锁。

看这里:static final Object o = new Object();

只需将对象设为最终对象,以确保您不会在代码中的其他任何地方错误/有意地分配新值。您可以直接以同步方式使用此对象以确保线程安全。

于 2013-08-14T07:16:23.800 回答
0

这是否意味着第一个进入的线程将与第三个线程共享锁?

是的,此外,由于:

  1. 非易失性static int counter = 0变量
  2. 非原子操作++

每个线程都有自己的 variable 副本counter。这意味着以下情况永远不会true

if ( counter++ == 1 )    
   o = new Object();

这就是为什么所有这些线程o在声明o.

于 2013-08-14T08:57:34.923 回答