不应该阻止来自所有类实例的类阻塞线程

时间:2011-06-16 10:24:27

标签: java thread-safety

public class Fern extends Thread
{
    private String x = "varun"; 

    public void run()
    {
         synchronized(Fern.class){

        System.out.println(x);
        try {
            sleep(5);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        x = "Anku";
        }
    }
    public static void main(String args[]) throws Exception 
    {
        Fern f = new Fern();
        Thread t1 = new Thread(new Fern());
        Thread t2 = new Thread(new Fern());
        t1.start();
        t2.start();
    }
}

输出是: VARUN VARUN

由于块已经在Fern.class上同步,因此只允许一个线程一次进入块,而不管它属于哪个实例,因为对于所有实例,该类只有一个锁。如果我用一个Fern对象替换Thread构造函数中的新Fern(),则输出为: VARUN Anku。 这种行为就是我曾经同步过的(这个)。 我不明白为什么会发生这种情况,因为我已经同步了

5 个答案:

答案 0 :(得分:3)

x不是static变量。将其更改为static

  

static String x =“varun”;


修改: 或将相同的对象作为参数传递给t1t2

Fern f = new Fern();
Thread t1 = new Thread(f); // pass the same object
Thread t2 = new Thread(f);

答案 1 :(得分:2)

x是一个实例变量 - 换句话说,即使一次只有一个线程可以进入该块,它们也会查看不同的变量。更改第一个线程中x的值不会影响第二个线程正在查看的x

换句话说,同步是“正确的”(如果您不希望多个线程进入该块,无论实例如何),但您的数据访问没有按照您的想法进行应该。

作为旁注,我个人更喜欢锁定我的班级只能 的参考文献。

作为另一个旁注,如果Fern实施Runnable而不是扩展Thread会更好 - 您当前正在将一个线程传递给另一个线程构造函数,没有多大意义......

答案 2 :(得分:2)

线程的每个实例中的x是不同的。在这两种情况下,请private static String x使用共享的x

答案 3 :(得分:1)

这与同步无关。 x是一个实例变量,因此每个Fern实例都有自己的副本,初始化为“varun”,然后打印,然后设置为“Anku”。

答案 4 :(得分:0)

因为您有两个不同的Fern个实例,所以其中一个实例更改了其x字段的值这一事实并未见到另一个实例。 (我猜,因为你没有给出x的声明。要获得更好的答案,只发布完整的代码。)