同步静态变量

时间:2014-05-01 09:16:34

标签: java multithreading

通过同步作为变量的静态对象我理解的是,如果一个线程正在访问它,其他线程就不能。

    class T3
    {
    static Integer i = 0;

    static void callStatic()
    {
        synchronized(T3.class)
        {
            System.out.println(i++);
            while(true);
        }
    }

    public void notStatic()
    {
        System.out.println(i++);
        while(true);
    }
    }

    class T2 implements Runnable
{
    public void run()
    {
        System.out.println("calling nonstatic");
        new T3().notStatic();
    }
}

class T implements Runnable
{
    public void run()
    {
        System.out.println("calling static");
        T3.callStatic();
    }
}

public class Test
{
    public static void main(String[] args)
    {
        new Thread(new T()).start();
        try
        {
            Thread.sleep(100);
        }
        catch (InterruptedException e)
        {
        }
        new Thread(new T2()).start();
    }
}

但是这个演示程序输出为:

  

调用静态

     

0

     

调用非静态

     

1

我的理解错了吗?或者我错过了什么?

我尝试过,同步callStatic方法,同步T3.class类对象。但没有一个像我想的那样有效。

注意:我认为,1不会被打印,因为callStatic已锁定变量i并处于无限循环中。

3 个答案:

答案 0 :(得分:3)

您不要对变量进行同步,而是在对象上进行同步。

callStatic1上同步,然后将i设置为2。如果notStatic此时要输入synchronized(i)块,它将在2上同步。没有其他线程锁定2,所以它继续。

(实际上,12不是对象,但Integer.valueOf(1)Integer.valueOf(2)会返回对象,编译器会自动插入Integer.valueOf调用将int转换为Integer s)

在您的代码中,notStatic根本没有实际同步。确实,在特定时间只有一个线程可以位于特定对象的synchronized块中,但这对于未尝试输入synchronized块的其他线程没有影响

答案 1 :(得分:1)

静态和非静态上的同步块不会相互阻塞。您需要了解synchronized如何为此工作。始终在永远不在变量上的对象上完成同步。同步时,线程会锁定对象的监视器,即放在synchronized语句中的对象。

静态引用上的同步块(如代码中的)会锁定类的.class对象,而不是该类的任何实例。因此,静态和非静态同步块不会相互阻塞。

现在,在您的代码中,notStatic方法不会在callStatic在静态i Integer对象上同步的任何内容上进行同步。所以他们不会互相阻挡。

答案 2 :(得分:1)

注意:此答案与synchronized(i)synchronized(T3.class)而非callStatic的原始问题有关。编辑确实改变了问题。


synchronize作用于对象,而不是持有它的变量/成员。您的代码中有一些重要的事情发生。

  • synchronize(i)确实会同步对i 提供的的访问,而其他尝试使用它的代码也会同步。它对不同步的代码没有影响。假设线程A执行synchronize(i)并保持它(你的无限循环);然后线程B确实System.out.println(i);线程B可以愉快地读取i,没有什么能阻止它。线程B必须做

    synchronize (i) {
        System.out.println(i);
    }
    

    ...为了受到主题A synchronize(i)的影响。您的代码是(尝试)同步变异,但不能访问。

  • 带有i++;
  • Integer实际上等同于i = new Integer(i.intValue() + 1),因为Integer是不可变的。因此,它会创建一个不同的 Integer对象,并将其存储在i成员中。因此,在 Integer对象上进行同步的任何操作都不会影响 new 上的代码同步。因此,即使您的代码同步访问和变异,也没关系,因为同步将在旧对象上。

    这意味着callStatic中的代码正在Integer的实例上进行同步,然后重复创建一堆其他实例,而这些实例未进行同步。