1

我正在准备 Java SE 7 程序员 II 考试。在其中一个模拟考试中,有一个练习可以从代码遭受的线程问题中找出答案。这是代码:

public class Test {

    public static void main(String[] args) {
        final Counter obj1 = new Counter("obj1");
        final Counter obj2 = new Counter("obj2");

        new Thread(new Runnable() {
            @Override
            public void run() {
                Thread.currentThread().setName("first");
                obj1.display(obj2);
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                Thread.currentThread().setName("second");
                obj2.display(obj1);
            }
        }).start();
    }
}

class Counter extends Thread {
    int i = 10;
    String name;

    public Counter(String name) {
        this.name = name;
    }

    public synchronized void display(Counter obj) {
        try {
            Thread.sleep(5);
            obj.increment(this);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void increment(Counter obj) {
        System.out.println(++i);
    }
}

他们说这是活锁。我看不到。请有人可以更详细地解释一下。

4

4 回答 4

3

根据维基百科的定义,我不会将此定义为活锁

活锁类似于死锁,除了活锁中涉及的进程的状态不断地相互改变,没有进展。

虽然它确实符合死锁的定义

在操作系统中,死锁是当一个进程或线程进入等待状态时发生的一种情况,因为请求的资源被另一个等待的进程持有,而另一个等待的进程又在等待另一个资源。如果一个进程不能无限期地改变它的状态,因为它请求的资源正被另一个等待的进程使用,那么系统就被称为死锁。

你的第一个线程有锁obj1,第二个有锁obj2,然后他们请求另一个锁并阻塞。

于 2014-07-07T14:53:18.570 回答
1

检查线程状态后,我现在确定这是一个死锁!

我将线程存储在本地t1t2调用该getState()方法。

System.out.println(t*.getState())启动线程后立即调用,打印:TIMED_WAITING

在 ,之后display方法中相同,打印:RUNNABLEThread.sleep(5)

现在是关键部分:

再次调用System.out.println(t*.getState())(对于线程t1t2),main但这次在 a 之后sleep(5000)将打印BLOCKED

阻塞的意思是:等待获取锁,这意味着它是一个死锁!

于 2014-07-08T08:48:22.037 回答
0

以下是每个线程的工作方式:

  1. 获得一个对象上的锁 - 发生在run线程的方法中,因为Counter.displayis synchronized
  2. 称之为display方法。
  3. 获得另一个对象的锁——准备调用另一个increment对象的方法,因为该方法是.incrementsynchronized
  4. 调用另一个增量并要求它增加自己的对象 - 奇怪,但不会导致死锁。

除了不设置ivolatile 因为它可以以多线程方式访问的问题之外,这里还有许多与锁相关的问题,但主要的问题是:

1在stage 请求锁之前,不会释放step 中持有3的锁。对我来说,这是一个潜在的死锁,因为如果两个线程都1在另一个命中之前通过阶段,它们就会锁定3。但是,只要两个线程从未遇到过问题,就可以实际工作正常,因此可以将其解释为活锁,因为两个线程可以愉快地一起运行一段时间,然后最终致命地拥抱。

所以我会称这种潜在的僵局,并让学究们决定如何称呼它。

于 2014-07-07T15:38:44.240 回答
0

运行上面的程序并获得
第一个线程的线程转储

"first@573" prio=5 tid=0xb nid=NA waiting for monitor entry
  java.lang.Thread.State: BLOCKED
     blocks second@575
     waiting for second@575 to release lock on <0x245> (a dp.Counter)
      at dp.Counter.increment(LiveLock.java:44)
      at dp.Counter.display(LiveLock.java:37)
      - locked <0x246> (a dp.Counter)
      at dp.LiveLock.lambda$main$0(LiveLock.java:15)
      at dp.LiveLock$$Lambda$1.16460856.run(Unknown Source:-1)
      at java.lang.Thread.run(Thread.java:745)

对于第二个线程

"second@575" prio=5 tid=0xc nid=NA waiting for monitor entry
  java.lang.Thread.State: BLOCKED
     blocks first@573
     waiting for first@573 to release lock on <0x246> (a dp.Counter)
      at dp.Counter.increment(LiveLock.java:44)
      at dp.Counter.display(LiveLock.java:37)
      - locked <0x245> (a dp.Counter)
      at dp.LiveLock.lambda$main$1(LiveLock.java:20)
      at dp.LiveLock$$Lambda$2.23661220.run(Unknown Source:-1)
      at java.lang.Thread.run(Thread.java:745)

看起来像僵局的情况。

于 2015-02-26T04:19:48.937 回答