java和threads:中断的异常以及如何正确使用BlockingQueue的take()方法

时间:2022-02-28 20:57:42

What exactly happens when there is nothing on the queue and a take() is called. The API says the method will wait but does that mean the CPU spins checking for empty/not empty until an item is on the queue or does it mean that the thread yields and will be awoken by an interrupt? If it is the case of the former, I would probably want to see if the queue is empty and if it is call thread.yield() to give up processor time. My question is really do I need to call yield or does some inner mechanism handle that for me?

当队列中没有任何内容并调用take()时会发生什么。 API表示该方法将等待,但这是否意味着CPU在队列中出现一个项目或者是否意味着线程会被中断唤醒之前,旋转检查是否为空/非空?如果是前者的情况,我可能想看看队列是否为空以及是否调用thread.yield()来放弃处理器时间。我的问题是,我是否需要调用yield或者是否有一些内部机制为我处理?

Secondly, what is the interrupted exception meant for? If I understand correctly it means that if thread A is executing this method and is waiting for input and another thread B calls threadA.interrupt() then thread A will catch the interrupted exception and presumably pause execution, if it is nice. Is that the correct way of thinking about it?

其次,中断的异常意味着什么?如果我理解正确,这意味着如果线程A正在执行此方法并且正在等待输入而另一个线程B调用threadA.interrupt(),那么线程A将捕获中断的异常并且可能会暂停执行,如果它很好的话。这是正确的思考方式吗?

3 个解决方案

#1


Note that BlockingQueue is an interface. So what follows is implementation dependent. If you look at the source code for (say) LinkedBlockingQueue, the source for take() calls lockInterruptibly() on a RentrantLock. From the doc for this:

请注意,BlockingQueue是一个接口。所以接下来是依赖于实现的。如果查看(例如)LinkedBlockingQueue的源代码,take()的源代码会在RentrantLock上调用lockInterruptibly()。从这个文件:

If the lock is not available then the current thread becomes disabled for thread scheduling purposes and lies dormant until one of two things happens:

如果锁不可用,那么当前线程将被禁用以进行线程调度,并且在发生以下两种情况之一之前处于休眠状态:

* The lock is acquired by the current thread; or
* Some other thread interrupts the current thread, and interruption of

lock acquisition is supported.

支持锁定获取。

I suspect there's be some wait()/notify() or similar going on. Will it spin the CPU ? No (check via top or similar)

我怀疑有一些wait()/ notify()或类似的东西正在进行中。它会旋转CPU吗?不(通过顶部或类似检查)

Re. your question on interrupts, the Java Specialist newsletter had a very interesting article on interrupt() and catching/handling the InterruptedException.

回覆。关于中断的问题,Java专家通讯有一篇关于interrupt()和捕获/处理InterruptedException的非常有趣的文章。

Read the article, but essentially if you catch the exception, you reinterrupt:

阅读文章,但基本上如果你发现异常,你重新开始:

  try {
        Thread.sleep(1000);
      } catch (InterruptedException ex) {
        Thread.currentThread().interrupt(); // very important
        break;
      }

#2


The wait() call does not spin, it typically uses OS services to wait for an event/condition - which puts the thread to sleep until the condition/event is signaled again. No processor time is used while waiting.

wait()调用不会旋转,它通常使用OS服务来等待事件/条件 - 这会使线程进入休眠状态,直到再次发出条件/事件信号。等待时不使用处理器时间。

You typically get the interrupted exception if the thread is blocking in a wait() call, and another thread calls interrupt() on that blocking thread, just like you said.

如果线程在wait()调用中阻塞,并且另一个线程在该阻塞线程上调用interrupt(),通常会得到中断的异常,就像你说的那样。

#3


It is considered a bad practice to call yield() as it cannot ensure niceness - you may call it and the scheduler instantly returns to your thread as it were a no-op. Use timed waits (e.g. wait(1000)) instead.

调用yield()被认为是一种不好的做法,因为它无法确保良好性 - 您可以调用它并且调度程序立即返回到您的线程,因为它是无操作。使用定时等待(例如等待(1000))。

Interruptions are a safe way to signal a thread that you want something from it - stop processing, wake up and respond to something, etc.

中断是一种安全的方式来向线程发出信号,告知您需要的东西 - 停止处理,唤醒和响应某些内容等。

In general, these things depend on your concrete scenarios. Java has some nice features about concurrency which can be more applicable to a situation.

一般来说,这些都取决于您的具体情况。 Java有一些很好的并发特性,可以更适用于某种情况。

#1


Note that BlockingQueue is an interface. So what follows is implementation dependent. If you look at the source code for (say) LinkedBlockingQueue, the source for take() calls lockInterruptibly() on a RentrantLock. From the doc for this:

请注意,BlockingQueue是一个接口。所以接下来是依赖于实现的。如果查看(例如)LinkedBlockingQueue的源代码,take()的源代码会在RentrantLock上调用lockInterruptibly()。从这个文件:

If the lock is not available then the current thread becomes disabled for thread scheduling purposes and lies dormant until one of two things happens:

如果锁不可用,那么当前线程将被禁用以进行线程调度,并且在发生以下两种情况之一之前处于休眠状态:

* The lock is acquired by the current thread; or
* Some other thread interrupts the current thread, and interruption of

lock acquisition is supported.

支持锁定获取。

I suspect there's be some wait()/notify() or similar going on. Will it spin the CPU ? No (check via top or similar)

我怀疑有一些wait()/ notify()或类似的东西正在进行中。它会旋转CPU吗?不(通过顶部或类似检查)

Re. your question on interrupts, the Java Specialist newsletter had a very interesting article on interrupt() and catching/handling the InterruptedException.

回覆。关于中断的问题,Java专家通讯有一篇关于interrupt()和捕获/处理InterruptedException的非常有趣的文章。

Read the article, but essentially if you catch the exception, you reinterrupt:

阅读文章,但基本上如果你发现异常,你重新开始:

  try {
        Thread.sleep(1000);
      } catch (InterruptedException ex) {
        Thread.currentThread().interrupt(); // very important
        break;
      }

#2


The wait() call does not spin, it typically uses OS services to wait for an event/condition - which puts the thread to sleep until the condition/event is signaled again. No processor time is used while waiting.

wait()调用不会旋转,它通常使用OS服务来等待事件/条件 - 这会使线程进入休眠状态,直到再次发出条件/事件信号。等待时不使用处理器时间。

You typically get the interrupted exception if the thread is blocking in a wait() call, and another thread calls interrupt() on that blocking thread, just like you said.

如果线程在wait()调用中阻塞,并且另一个线程在该阻塞线程上调用interrupt(),通常会得到中断的异常,就像你说的那样。

#3


It is considered a bad practice to call yield() as it cannot ensure niceness - you may call it and the scheduler instantly returns to your thread as it were a no-op. Use timed waits (e.g. wait(1000)) instead.

调用yield()被认为是一种不好的做法,因为它无法确保良好性 - 您可以调用它并且调度程序立即返回到您的线程,因为它是无操作。使用定时等待(例如等待(1000))。

Interruptions are a safe way to signal a thread that you want something from it - stop processing, wake up and respond to something, etc.

中断是一种安全的方式来向线程发出信号,告知您需要的东西 - 停止处理,唤醒和响应某些内容等。

In general, these things depend on your concrete scenarios. Java has some nice features about concurrency which can be more applicable to a situation.

一般来说,这些都取决于您的具体情况。 Java有一些很好的并发特性,可以更适用于某种情况。