我一直以为,所有线程对锁的竞争是公平的,是随机的。我写了个小例子,结果让我不解。
按照下面的代码执行,结果确实是随机的,运行多次会得到不同的结果,这恰好说明了对锁的竞争是随机的。但是,若将第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();
}
}
}多线程竞争
按照下面的代码执行,结果确实是随机的,运行多次会得到不同的结果,这恰好说明了对锁的竞争是随机的。但是,若将第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();
}
}
}多线程竞争
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
只是个人猜测!!!!!
《深入JVM锁机制1-synchronized 》
http://blog.csdn.net/chen77716/article/details/6618779
Thread-3
Thread-1
Thread-2
请按任意键继续. . .这是我运行的结果,我是2核的机器。多次运行结果重复概率很大。不过我觉得 循环次数太少 如果你改成10,你得到的结果就很不同了。我猜测与JVM的机制有关,尽管说线程是公平竞争的。但是再怎么公平也有个“先来后到”的感觉,那么这个先来后到,我猜测是循环中运行start,但这个线程何时进入就绪状态 却是随机的。
我这个例子,锁的争夺就是按照栈的方式进行的,后进先出,严格有序,但这就没有公平性了,若不停地有新的线程来抢夺锁,那不是第一个进栈的线程永远也得不到锁了?
你说的随机性【ldh911】已经解释的很清楚了,对于你的疑惑我简单的说一下
1.非公平锁的效率比公平锁要高 这就是JVM中为什么使用的原因。
2.后来的线程先获得锁这就是非公平的体现,不停的来新线程是一种合理的推测,不是一种合理的应用,并且操作系统对线程的数量也有大小规定。
3.如果你的运用需要使用像公平锁一样的效果可以使用Lock下的FairSync类,另外闭锁,栅栏等也可以帮助你灵活的实现业务中的需求。
4.饥饿死锁确实存在但一般是由你程序没有快速释放造成而并非JVM的原因。
每次插入和获取都在链表头操作,用CAS硬件指令实现,这样就不用调用操作系统锁来实现对链表的同步访问。
这是一种权衡吧,虽然丧失了公平性,但提高了效率。