Java线程:使用sleep和interrupt而不是wait和notifyAll

时间:2014-05-02 20:30:46

标签: java multithreading

场景 - 尝试使用sleep()interrupt()获得结果;哪一个 本来是由wait()notifyAll()

完成的

问题 - 我知道这种方式不是首选。你们能告诉我这样做有什么不妥吗? 场景。

一个原因是 notifyAll()通知所有寻找该对象锁定的线程。但是interrupt() 我们明确地在每个等待的线程上有调用中断。

其他原因是不同的线程无法更改对象状态。这里是初始线程本身 food=true抓住InterruptedException。但那有什么问题?

/**
 * Objective of this program:
 * 
 * I was thinking, why can't we achieve the guarded block with Sleep and Interrupt,
 * why only with wait and notify..
 * 
 * Wait releases lock; while Sleep does not . But both suspend the execution. 
 * So if you are synchronizing on the object, then we cannot have the second thread
 * to modify the object state due the lock on the object, and the second thread cannot acquire it.
 * 
 * So I did a explicit interrupt on the first thread.
 * 
 */
/**
 * 
 * One person ask if he has something to eat polling the "food" variable.
 * Another person updates the shared variable food.
 * 
 * food = true means the first person can start eating. food = false means he
 * has to wait and poll the value until food is available(food = true). This is
 * not a producer-consumer problem.
 * 
 */

public class _17GuardedBlockWithSleep_Interrupt_Badcase {

    static class Person {

        volatile boolean food;

        public boolean isFood() {
            return food;
        }

        public void setFood(boolean food) {
            this.food = food;
        }

        String name;

        Person(String name) {
            this.name = name;
        }

        /*
         * Sloppy/Bad way of implementation making it pause execution until it
         * gets interrupted. An interruption alone does not mean food is
         * available. May be interrupt was called by someone else who does not
         * provide food. So check the condition too.
         * 
         * Through sleep(), the execution is paused. CPU is free to take other
         * tasks, The lock on object is NOT released so other threads CANNOT
         * acquire the lock on the object.
         */

        // Guarded Block
        public synchronized void eatFood() {
            while (!isFood()) {
                // food is currently unavailable. I'm waiting..
                try {
                    /**
                     * Ideally we do wait() and notifyAll() in such a scenario. I am
                     * trying with Sleep and Interrupt.
                     */
                    Thread.sleep(1000000000);
                } catch (InterruptedException e) {
                    this.setFood(true);// it's not some other thread that provide food. it's itself!
                    System.out.println("eatFood() caught InterruptedException");
                    // e.printStackTrace();
                }
            }
            // if control comes here, then it means food is available
            System.out.println("got the food.. yummyy..thanks!");
        }

        public synchronized void provideFood(Thread t) {
            this.setFood(true); // this refers to current object. In this case, the
                                        // 'kuttappan' object
            // interrupt the first thread
            t.interrupt();
        }

    }

    public static void main(String[] args) {
        final Person kuttappan = new Person("Kuttappan");

        Runnable runnable1 = new Runnable() {
            @Override
            public void run() {
                /*
                 * if kuttappan is not already defined as final, you get an error
                 * "Cannot refer to a non-final variable kuttappan inside an inner class defined in a different method"
                 */
                kuttappan.eatFood();
                /*
                 * thread will try to acquire the lock on 'kuttappan' object when it
                 * invokes the synchronized method.
                 */
            }
        };
        final Thread t = new Thread(runnable1, "thread1");
        t.start();

        // someone is needed to make the food available for kuttappan.

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000); // 5 seconds
                    t.interrupt(); // MY IMPORTANT LINE
                    // kuttappan.provideFood(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

/**
 * OUTPUT:
 * 
 * Observe the line commented as "MY IMPORTANT LINE"
 * 
 * If you do 'kuttappan.provideFood(t);' then the program Keeps on running. no
 * output, because
 * 
 * The second thread cannot get into provideFood() of kuttappan object because
 * the first thread has not released the lock on the object!
 * 
 * But if you do t.interrupt(); the thread is interrupted and the program
 * behaves as expected.
 */

3 个答案:

答案 0 :(得分:2)

从这里开始:Difference between wait() and sleep()

"睡一个Thread 释放它所持有的锁,等待释放对wait()被调用的对象的锁定。&#34 ;

所以在你的情况下,似乎如果没有可用的食物,另一个线程就不可能进入并提供食物。

看来即使你打电话给t.interrupt(),第一个线程也会看到没有任何食物,所以它会再次入睡。我很可能会错误地解释这个... 正在努力...

没关系,我误读了你的部分代码。我认为部分问题在于您依靠原始线程本身来完成第二个线程应该完成的工作。所以你真的没有比单个线程添加食物然后消耗它更好...

答案 1 :(得分:1)

它是一个糟糕的选择,因为你指望一个线程每次捕获一个中断的异常。例外是IPC的高开销机制。可能有更多的原因,但这足以让它从生产代码中拉出来。

答案 2 :(得分:1)

我认为在您的场景中,生产者线程应始终引用消费者线程以便interrupt()它并且可以处理“事件”。

如果您使用wait() / notify(),则不需要线程相互了解,您只需要一个同步点 - 您等待/通知的对象。您也可以使用任意数量的线程共享此对象。所以最后生产者线程并不关心究竟是谁在等待资源,它只需要发送资源可用的信号。