多个线程因为得不到锁而阻塞,当锁被释放时,哪个线程会得到锁呢?

andycpp 2013-05-14 07:36:07
我一直以为,所有线程对锁的竞争是公平的,是随机的。我写了个小例子,结果让我不解。
按照下面的代码执行,结果确实是随机的,运行多次会得到不同的结果,这恰好说明了对锁的竞争是随机的。

但是,若将第7行的注释去掉,让第7行变得可用,即每隔1秒创建一个新线程参与竞争,当5秒后锁被释放,这些线程的执行顺序竟然是固定的,程序的运行结果永远是:
Thread-0
Thread-3
Thread-2
Thread-1
是的,我运行了100遍,永远是这个结果。多线程的随机性荡然无存,这是为什么????
为什么创建线程前,稍微休眠一下,就会丧失线程的随机性??
求高手解释。
代码如下:
public class Test {

public static void main(String[] args) throws Exception{
ShareObj obj = new ShareObj(5);
new MyThread(obj).start();
for(int i=0; i<3; i++) {
// TimeUnit.SECONDS.sleep(1);
new MyThread(obj).start();
}
}
}

class ShareObj {
private int sec;

public ShareObj(int sec) {
super();
this.sec = sec;
}

public synchronized void doSomething() throws Exception {
System.out.println(Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(sec);
sec = 0;
}
}

class MyThread extends Thread {

private ShareObj obj;

public MyThread(ShareObj obj) {
super();
this.obj = obj;
}

@Override
public void run() {
try {
obj.doSomething();
} catch (Exception e) {
e.printStackTrace();
}
}
}
...全文
1302 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
MiceRice 2013-05-16
  • 打赏
  • 举报
回复
引用 10 楼 andycpp 的回复:
你的解释我看懂了,这么解释很合理。 我这个例子,锁的争夺就是按照栈的方式进行的,后进先出,严格有序,但这就没有公平性了,若不停地有新的线程来抢夺锁,那不是第一个进栈的线程永远也得不到锁了?
11楼的同学解释了你关于公平性的问题。 6楼的同学给出的链接,解释了你关于“饿死”的问题。 其实很多问题、手段等都源自于《操作系统原理》。 基本上你可以放心,不公平性往往是局部的、短时性的,宏观上必然是公平的。
fei1710 2013-05-15
  • 打赏
  • 举报
回复
前面有个童鞋的链接已经详细的说明的锁的内部实现机制,等待队列就是一个链表。 每次插入和获取都在链表头操作,用CAS硬件指令实现,这样就不用调用操作系统锁来实现对链表的同步访问。 这是一种权衡吧,虽然丧失了公平性,但提高了效率。
xiajunsongfan 2013-05-15
  • 打赏
  • 举报
回复
引用 10 楼 andycpp 的回复:
[quote=引用 7 楼 ldh911 的回复:] 情况比较复杂,楼主你注释时看到的随机效果,不是锁的随机效果,而是线程调取抢占CPU时间片的随机效果。 而注释加上去后,线程必然按照固定顺序执行到 synchronized,此时才是真正体现锁的情况。锁的机制复杂得多,既要考虑公平性,又要考虑线程可执行条件。不过总体粗略来说,是队列结构。 另外,楼主最好用 单CPU单线程的环境测试,否则情况还会更复杂。
你的解释我看懂了,这么解释很合理。 我这个例子,锁的争夺就是按照栈的方式进行的,后进先出,严格有序,但这就没有公平性了,若不停地有新的线程来抢夺锁,那不是第一个进栈的线程永远也得不到锁了? [/quote] 你说的随机性【ldh911】已经解释的很清楚了,对于你的疑惑我简单的说一下 1.非公平锁的效率比公平锁要高 这就是JVM中为什么使用的原因。 2.后来的线程先获得锁这就是非公平的体现,不停的来新线程是一种合理的推测,不是一种合理的应用,并且操作系统对线程的数量也有大小规定。 3.如果你的运用需要使用像公平锁一样的效果可以使用Lock下的FairSync类,另外闭锁,栅栏等也可以帮助你灵活的实现业务中的需求。 4.饥饿死锁确实存在但一般是由你程序没有快速释放造成而并非JVM的原因。
andycpp 2013-05-15
  • 打赏
  • 举报
回复
引用 7 楼 ldh911 的回复:
情况比较复杂,楼主你注释时看到的随机效果,不是锁的随机效果,而是线程调取抢占CPU时间片的随机效果。 而注释加上去后,线程必然按照固定顺序执行到 synchronized,此时才是真正体现锁的情况。锁的机制复杂得多,既要考虑公平性,又要考虑线程可执行条件。不过总体粗略来说,是队列结构。 另外,楼主最好用 单CPU单线程的环境测试,否则情况还会更复杂。
你的解释我看懂了,这么解释很合理。 我这个例子,锁的争夺就是按照栈的方式进行的,后进先出,严格有序,但这就没有公平性了,若不停地有新的线程来抢夺锁,那不是第一个进栈的线程永远也得不到锁了?
andycpp 2013-05-15
  • 打赏
  • 举报
回复
引用 8 楼 N27741 的回复:
Thread-0 Thread-3 Thread-1 Thread-2 请按任意键继续. . . 这是我运行的结果,我是2核的机器。多次运行结果重复概率很大。 不过我觉得 循环次数太少 如果你改成10,你得到的结果就很不同了。 我猜测与JVM的机制有关,尽管说线程是公平竞争的。但是再怎么公平也有个“先来后到”的感觉, 那么这个先来后到,我猜测是循环中运行start,但这个线程何时进入就绪状态 却是随机的。
你把第7行的注释去掉,让第7行变为可以执行,结果还是随机的?
n27741 2013-05-15
  • 打赏
  • 举报
回复
Thread-0 Thread-3 Thread-1 Thread-2 请按任意键继续. . . 这是我运行的结果,我是2核的机器。多次运行结果重复概率很大。 不过我觉得 循环次数太少 如果你改成10,你得到的结果就很不同了。 我猜测与JVM的机制有关,尽管说线程是公平竞争的。但是再怎么公平也有个“先来后到”的感觉, 那么这个先来后到,我猜测是循环中运行start,但这个线程何时进入就绪状态 却是随机的。
MiceRice 2013-05-14
  • 打赏
  • 举报
回复
情况比较复杂,楼主你注释时看到的随机效果,不是锁的随机效果,而是线程调取抢占CPU时间片的随机效果。 而注释加上去后,线程必然按照固定顺序执行到 synchronized,此时才是真正体现锁的情况。锁的机制复杂得多,既要考虑公平性,又要考虑线程可执行条件。不过总体粗略来说,是队列结构。 另外,楼主最好用 单CPU单线程的环境测试,否则情况还会更复杂。
zhaogang 2013-05-14
  • 打赏
  • 举报
回复
LZ 看看这里 《深入JVM锁机制1-synchronized 》 http://blog.csdn.net/chen77716/article/details/6618779
桃园闲人 2013-05-14
  • 打赏
  • 举报
回复
没做过这方面的测试,个人觉得是不是没有休眠,线程中输出的内容太快,以至于通过IO向控制台打印时,控制台无法同一时刻打印多条记录,JVM在这一层做了一个线程池,并做了优先级处理。也就是说线程还是随机运行的,公平竞争的,只是在输出控制台这里被做了优先级排序。 呵呵。。。 只是个人猜测!!!!!
zhaogang 2013-05-14
  • 打赏
  • 举报
回复
LZ,改变睡眠时间,结果会改变。
SRCIsGrowing 2013-05-14
  • 打赏
  • 举报
回复
每次运行均出现以下,(无论是否注释第七行) Thread-0 Thread-3 Thread-2 Thread-1 个人认为,打开第七行的意义是使得Thread.start()有足够时间得到CPU资源,每一个thread将会顺序得进入ContentionList. 如果不打开第7行,Thread进入ContentionList的顺序有可能不一样。因为Thread.start()CPU有可能分配的CPU资源不一样。 仅仅猜测,没有看过start,在JVM中的具体实现。 你的这个帖子,和我发的帖子的问题非常相近。本人刚开始学习JAVA,关注中。。。 http://bbs.csdn.net/topics/390458017?page=1#post-394485275
傲世孤尘 2013-05-14
  • 打赏
  • 举报
回复
好吧,以前没想这么多 现在试试
傲世孤尘 2013-05-14
  • 打赏
  • 举报
回复
运行了一百遍。。。。 好吧,我来试试

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧