Java线程:使用sleep和interrupt而不是wait和notifyAll [英] Java Threads: Using sleep and interrupt rather than wait and notifyAll

查看:200
本文介绍了Java线程:使用sleep和interrupt而不是wait和notifyAll的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

场景 - 尝试使用 sleep()中断();哪个
本来是由 wait() notifyAll()

Scenario - Trying to achieve the result with sleep() and interrupt(); which would have been otherwise done by wait() and notifyAll()

问题 - 我知道这种方式不是首选。在下面的
场景中,你能告诉我这样做有什么问题。

Question - I know this way is not preferred. Can you guys please let me know what is wrong in doing like this in this below scenario.

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

One reason is notifyAll() notify all threads looking for the lock on that object. But with interrupt() we have the invoke interrupt on each waiting thread explicitly.

其他原因是不同的线程无法更改对象状态。在这里,初始线程本身会在捕获 InterruptedException 时产生
food = true 。但这有什么问题?

Other reason is that a different thread cannot change the object state. Here the initial thread itself make food=true on catching an InterruptedException. But what is wrong with that?

/**
 * 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.
 */


推荐答案

从这里: wait()和sleep()之间的区别

睡一个线程 释放它所持有的锁,等待释放 wait()被调用。

"Sleeping a Thread does not release the locks it holds, while waiting releases the lock on the object that wait() is called on."

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

So in your case it appears that if there is no food available it's impossible for another thread to go in and make food available.

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

It also appears that even if you call t.interrupt(), the first thread will just see that there isn't any food, so it'll sleep again. I could very well be interpreting this incorrectly though... working on this...

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

Never mind, I misread part of your code. I think part of the problem is that you rely on the original thread itself to do the work that the second thread should have done. So really you're not doing much better than having a single thread add food then consume it...

这篇关于Java线程:使用sleep和interrupt而不是wait和notifyAll的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆