提问者:小点点

在这个同步块中发生了什么


我试图在synchronized块之前查看变量值是否可以由多个线程修改。我对下面代码的行为感到困惑。我创建了一个有同步的块的方法,如下所示

public void testMethod( String x )
{
    String myX = x.toUpperCase();
    System.out.println( myX ); // Prints the value before the critical section
    synchronized( this )
    {
        try
        {
            Thread.sleep( 5000 );
        }
        catch( InterruptedException e )
        {
            e.printStackTrace();
        }
        System.out.println( myX ); // Prints the value inside the critical section
    }
}

然后,我创建了两个线程,用两个不同的字符串值调用这个方法,如下所示,

Thread myThreadOne = new Thread( () -> testMethod( "T1" ) );
Thread myThreadTwo = new Thread( () -> testMethod( "T2" ) );

并在main方法内调用。

public static void main( String[] args )
{
    Test t1 = new Test();
    t1.myThreadOne.start();
    t1.myThreadTwo.start();
}

现在我期望的输出是类似于T1T2T2T2。或者,无论哪个线程最后启动,都应该在synchronized块之前和内部打印值,因为很明显,变量myX将在第一个线程处于睡眠状态或第一个线程处于临界段内时具有来自第二个线程的更新值。

但是输出总是第一个线程值,后面跟着第二个线程值。像T1T2T1T2。怎么会发生这种事?在同步块之外,第二个线程没有修改这个值。还是我的示例代码有问题??


共2个答案

匿名用户

您需要在方法之外声明myx变量:

String myX;

    public void testMethod( String x )
    {
        myX = x.toUpperCase();
        System.out.println( myX ); // Prints the value before the critical section
        synchronized( this )
        {
            try
            {
                Thread.sleep( 5000 );
            }
            catch( InterruptedException e )
            {
                e.printStackTrace();
            }
            System.out.println( myX ); // Prints the value inside the critical section
        }
    }

这将给你你想要的结果。

原因:

  • 局部变量本质上是线程安全的,不被线程共享
  • 而类变量是共享的

你可以看看这个:为什么局部变量线程安全在Java

匿名用户

字符串myX是一个局部变量,这意味着当每个线程执行testMethod(字符串x)时,它将创建一个对任何其他线程都不可见的唯一副本。

如果您想更改myX,我建议使用全局变量。