java如何实现“自旋”(spin)

我本以为Thread.yield()是实现自旋的,不过yield()会放弃cpu时间片,那应该也会进行上下文切换吧?那就不是自旋了吧?(我理解的自旋是:当线程需要某个资源,但这个资源没有到位,这时就进行一个死循环,从而不放弃cpu执行时间,也不进行上下文切换)

那,我该怎么实现自旋呢?

阅读 15.8k
2 个回答

一个简单的while就可以满足你的要求。

目前的JVM实现自旋会消耗CPU,如果长时间不调用doNotify方法,doWait方法会一直自旋,CPU会消耗太大。

public class MyWaitNotify3{

  MonitorObject myMonitorObject = new MonitorObject();
  boolean wasSignalled = false;

  public void doWait(){
    synchronized(myMonitorObject){
      while(!wasSignalled){
        try{
          myMonitorObject.wait();
         } catch(InterruptedException e){...}
      }
      //clear signal and continue running.
      wasSignalled = false;
    }
  }

  public void doNotify(){
    synchronized(myMonitorObject){
      wasSignalled = true;
      myMonitorObject.notify();
    }
  }
}

请参考 这里, 假唤醒部分。

个人觉得wait/notify是条件变量的一种,并不是操作系统意义上的自旋,自旋应该是一个空loop,当loop的条件被其他线程改变时再进入临界区,参考java锁的种类以及辨析(一):自旋锁,其中如果觉得空循环耗CPU,方法体里加上Thread.yield()。譬如以下是一个顺序打印ABC的程序:

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

public class CharacterPrint implements Runnable {

    private int state = 0;
    private final int COUNT = 10;

    private String[] chs = { "A", "B", "C", "D" };
    private final int N = chs.length;

    private Lock lock = new ReentrantLock();

    private CharacterPrint() {
    }

    @Override
    public void run() {
        for (int i = 0; i < N; i++) {
            createThread(i);
        }
    }

    private void createThread(final int i) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (state != i) {
                        Thread.yield();
                    }
                    ;
                    lock.lock();
                    for (int j = 0; j < COUNT; j++) {
                        System.out.println(chs[i]);
                    }
                    state = (i + 1) % N;
                } finally {
                    lock.unlock();
                }
            }
        }, "thread" + i).start();
    }

    public static void main(String[] args) {
        new CharacterPrint().run();
    }
}

最后想说,一直都不太清楚自旋锁和条件变量差在哪里,但在posix的规范里它们就是不同的东西,参考同步和互斥的POSXI支持(互斥锁,条件变量,自旋锁)

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏