为什么线程在释放锁之后仍然运行?

时间:2014-12-04 16:34:20

标签: java synchronization deadlock

这是关于Lock对象的Oracle java教程中的示例。有人请确认我是否正确解释了代码。

我只考虑第一个线程,因为另一个线程的工作方式相同。

首先,它获取alphonse的锁,并访问方法impendingBow。该方法现在尝试将两个实例的两个锁分配给线程。如果线程无法获取两个锁,则会释放它获取的锁。这是我坚持的时候。如果线程释放锁,另一个可以访问这两个实例,并且第一个线程应该在释放锁之后立即停止执行。但事实上并非如此。它仍然返回布尔值并继续在bow方法中运行else语句。为什么会发生这种情况?我认为就像同步代码一样,线程应该停止执行,直到它再次获得锁定。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Random;

public class Safelock {
    static class Friend {
        private final String name;
        private final Lock lock = new ReentrantLock();

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

        public String getName() {
            return this.name;
        }

        public boolean impendingBow(Friend bower) {
            Boolean myLock = false;
            Boolean yourLock = false;
            try {
                myLock = lock.tryLock();
                yourLock = bower.lock.tryLock();
            } finally {
                if (! (myLock && yourLock)) {
                    if (myLock) {
                        lock.unlock();
                    }
                    if (yourLock) {
                        bower.lock.unlock();
                    }
                }
            }
            return myLock && yourLock;
        }

        public void bow(Friend bower) {
            if (impendingBow(bower)) {
                try {
                    System.out.format("%s: %s has"
                        + " bowed to me!%n",
                        this.name, bower.getName());
                    bower.bowBack(this);
                } finally {
                    lock.unlock();
                    bower.lock.unlock();
                }
            } else {
                System.out.format("%s: %s started"
                    + " to bow to me, but saw that"
                    + " I was already bowing to"
                    + " him.%n",
                    this.name, bower.getName());
            }
        }

        public void bowBack(Friend bower) {
            System.out.format("%s: %s has" +
                " bowed back to me!%n",
                this.name, bower.getName());
        }
    }

    static class BowLoop implements Runnable {
        private Friend bower;
        private Friend bowee;

        public BowLoop(Friend bower, Friend bowee) {
            this.bower = bower;
            this.bowee = bowee;
        }

        public void run() {
            Random random = new Random();
            for (int n = 0; n <5;n++) {
                try {
                    Thread.sleep(Math.round(Math.random()*1000));
                } catch (InterruptedException e) {}
                bowee.bow(bower);
            }
        }
    }


    public static void main(String[] args) {
        final Friend alphonse =
            new Friend("Alphonse");
        final Friend gaston =
            new Friend("Gaston");
        new Thread(new BowLoop(alphonse, gaston)).start();
        new Thread(new BowLoop(gaston, alphonse)).start();
    }
}

2 个答案:

答案 0 :(得分:0)

线程在释放锁定时不会停止执行。如果出现以下情况则停止执行:

  1. 它试图锁定锁但不能(因为你使用了trylock而不能在这里停止执行)
  2. 明确地产生控制,例如通过睡觉(睡觉())
  3. 调度程序现在决定它更喜欢其他线程。对于所有意图和目的,您应该假设这是一个随机事件。
  4. 这些都不会发生在这里,所以一个线程继续执行直到3)发生。

答案 1 :(得分:0)

同步块之间存在细微差别,Lock.lock()Lock.tryLock()Lock.tryLock(timeout)

tryLock方法只有在调用时没有被另一个线程持有时才获取锁。因此,当它无法获得锁定时,它会立即返回。

lock方法将等待锁定可用,同时等待该线程处于休眠状态。将代码与synchronized语句同步也是如此。该线程将一直等到它可以获取该代码块的锁定。

tryLock(timeout)方法将等待锁定可用或超时到期。

或多或少在javadoc中描述:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html

对于您期望的行为,您可以使用tryLock更改lock语句,并且您会注意到线程最终会陷入死锁。

相关问题