将`Thread.yield()`插入同步函数时会发生什么

时间:2018-06-04 09:59:24

标签: java multithreading task synchronized

我正在学习Java中的多线程。以下是演示代码,我对函数内Thread.yield()的使用感到好奇。

它不是同步函数,在运行任务完成其工作之前无法调用它吗?然后将Thread.yield()插入此块之间有什么区别?

演示代码:

public class SynchronizeEvenGenerator {
private int currentEvenValue = 0;
/**
 * Generate even and return it
 * @return
 */
public synchronized int next() {
    ++currentEvenValue;
    Thread.yield();
    ++currentEvenValue;
    return currentEvenValue;
    }
}

2 个答案:

答案 0 :(得分:3)

  

如果在同步函数中调用Thread.yield()会发生什么?

Thread.yield()状态为javadoc

  

" [这是]调度程序提示当前线程愿意产生其当前使用的处理器。调度程序可以忽略此提示。"

所以有两种可能性:

  1. 什么都没发生;即yield()电话会立即返回。
  2. 计划另一个线程并开始执行。最终,此线程被重新安排,yield()调用返回。
  3. 不会发生一件事。线程放弃互斥锁。碰巧被阻止等待获取互斥锁的任何其他线程将保持被阻止。

      

    它不是一个同步方法,在运行任务完成其工作之前无法调用吗?

    Thread.yield不是同步方法。 (即使它是,它将锁定Thread对象,而不是synchronized块当前持有的锁。)

    因此,在您的示例中,对next()的调用保证将计数器正好递增2.如果某个其他线程调用next()方法,则第二个调用将保持阻塞状态(至少)在第一次通话后返回。

    javadoc也说了这个:

      

    "使用此方法很少合适。"

      

    另一个问题:它是否会成为线程调度的死锁

    没有。调用yield()的线程最终将被重新安排。

    (死锁是一种非常具体的现象(参见Wikipedia article),只有在获得锁定时才会发生。当一个线程产生时,它既不会获取或释放锁定,也不会导致死锁。)

    现在,当一个线程产生时,它可能需要很长时间再次被调度,特别是如果有许多其他可运行的线程处于相同的或更高的优先级。最终结果是等待获取锁的其他线程可能会持续很长时间。这可能会过度增加争用和拥塞。但最终,yield()调用将返回,next()调用将返回,另一个线程将能够获取锁。

    简而言之:在持有锁时调用yield()对性能不利,但它不会直接导致死锁。

    正如javadoc所说,调用yield()很少适合。

答案 1 :(得分:1)

  

这是不是一个同步函数,在运行任务完成它之前无法调用它?

它不能在同一个对象的另一个线程中运行。

  

然后将Thread.yield()插入此块之间的差异是什么?

正在运行线程的CPU可以上下文切换到系统上任何进程的另一个可用线程。

如果没有等待线程运行,它将使其慢约15-30微秒。

c.f。 wait(0),这可以允许另一个线程获得锁。