【问题标题】:How could the two threads enter the synchronized block at the same time?两个线程怎么可能同时进入同步块呢?
【发布时间】:2013-09-12 20:14:49
【问题描述】:

发生了一些奇怪的事情。当我进入同步块时,我尝试打印线程的名称。在打印语句之后,我暂停了 100000 秒。

@Override
public int getNextAvailableVm() {
    synchronized(this) {

        System.out.println(Thread.currentThread().getName());

        try {Thread.sleep(100000000);}catch(Exception exc){}

        String dataCenter = dcc.getDataCenterName();
        int totalVMs = Temp_Algo_Static_Var.vmCountMap.get(dataCenter);
        AlgoHelper ah = (AlgoHelper)Temp_Algo_Static_Var.map.get(dataCenter);
        .
        .
        .
   }
}

但是在运行此方法时,会打印 2 个线程的名称。

Thread-11
Thread-13

在此之后出现长时间的停顿。这是为什么 ?当第一个线程尚未离开同步块时,两个线程如何进入同步块?

【问题讨论】:

  • 你确定你在同一个对象上调用getNextAvailableVm()吗?
  • 你确定你的睡眠没有被打扰? (在异常块中打印一些东西)
  • @njzk2 没有从异常块中打印出来
  • @SuhailGupta : 可能是因为没有打印声明?
  • @rocketboy 评论可能是你的问题。如果在同一个对象上正确同步,则没有理由应该由多个线程访问该块

标签: java multithreading synchronized


【解决方案1】:

如果两个线程针对同一个对象运行,那么这不应该发生。

因此,我建议为每个线程创建一个新对象,或者至少有一些线程在不同的对象上运行。

如果你确实想要多个对象,那么你应该使用synchronized(this),你应该创建一个static final Objectsynchronize on。请不要在 this.getClass() 上同步,因为那样会中断。

【讨论】:

  • this.getClass() 上的同步如何中断?在 ClassName.class 上同步也是如此吗?
  • @JensSchauder - 如果您在this.getClass 上进行同步,那么当其中任何 个对象同步时,该类型的所有 个对象将被阻塞。此外,您的对象的子类将无法与超类的对象正确同步。这几乎肯定不是你想要的。
【解决方案2】:

您很可能在包含类的不同实例上调用getNextAvailableVm()。由于您在 this 上同步,您将锁定两个不同的监视器(第一个线程锁定在 instance1 上,第二个线程锁定在 instance2 上)。

有很多方法可以纠正这个问题:

  • 制作整个方法synchronized
  • this.getClass()上同步
  • 定义要锁定的静态对象
  • 使用 java.util.concurrent.locks 中的方法进行锁定

这些只是解决您的问题的一些建议,但要找到合适的建议,我们必须更多地了解您的应用程序结构和您的要求。

【讨论】:

  • 不要在getClass() 上同步。如果您开始包含子类,那将会中断。
【解决方案3】:

我猜下面的程序会像你预期的那样工作,

锁在Thread1.Class上,两个线程不会同时执行方法

public class Test {
    public static void main(String [] args) { 
        Thread1 t1 = new Thread1();
        Thread1 t2 = new Thread1();
        t1.start();
        t2.start();
    }
}

class Thread1 extends Thread{
    public void run(){
        getNextAvailableVm();
    }
    public void getNextAvailableVm() {
        synchronized(Thread1.class) {
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
                }catch(Exception exc){}
            System.out.println(Thread.currentThread().getName());
        }

    }
}

输出 线程 1 线程 1 线程-0 线程-0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-02
    • 2019-02-27
    • 1970-01-01
    • 1970-01-01
    • 2016-01-31
    • 2017-05-03
    • 2014-04-30
    • 1970-01-01
    相关资源
    最近更新 更多