我本以为Thread.yield()是实现自旋的,不过yield()会放弃cpu时间片,那应该也会进行上下文切换吧?那就不是自旋了吧?(我理解的自旋是:当线程需要某个资源,但这个资源没有到位,这时就进行一个死循环,从而不放弃cpu执行时间,也不进行上下文切换)
那,我该怎么实现自旋呢?
我本以为Thread.yield()是实现自旋的,不过yield()会放弃cpu时间片,那应该也会进行上下文切换吧?那就不是自旋了吧?(我理解的自旋是:当线程需要某个资源,但这个资源没有到位,这时就进行一个死循环,从而不放弃cpu执行时间,也不进行上下文切换)
那,我该怎么实现自旋呢?
个人觉得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支持(互斥锁,条件变量,自旋锁)
12 回答5.9k 阅读
2 回答3.2k 阅读✓ 已解决
3 回答6.9k 阅读✓ 已解决
3 回答3k 阅读✓ 已解决
5 回答4.6k 阅读
4 回答2.3k 阅读
3 回答4.4k 阅读
一个简单的while就可以满足你的要求。
目前的JVM实现自旋会消耗CPU,如果长时间不调用doNotify方法,doWait方法会一直自旋,CPU会消耗太大。
请参考 这里, 假唤醒部分。