新手一枚,最近看孙鑫老师的Java视频,讲到多线程的时候,有这么一段代码。
class TicketsSystem
{
public static void main(String[] args)
{
SellThread st=new SellThread();

new Thread(st).start();
new Thread(st).start();
new Thread(st).start();
new Thread(st).start();
}
}class SellThread implements Runnable
{
int tickets=100;
Object obj=new Object();
public void run()
{
while(true)
{
synchronized(obj)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
if(tickets>0)
{

System.out.println("obj:"+Thread.currentThread().getName()+
" sell tickets:"+tickets);
tickets--;
}
}
}
}
}这四个线程分别叫T0,T1,T2,T3。在我理解看来:
1.T0锁定obj后,进入sleep 10ms,将运行权交给T1
2.T1发现obj被锁后,将运行权交给T2
3.同理T2交给T3,T3交还T0
4.此时T0往下运行,输出ticket号,然后解锁obj,由于是while(true),继续循环加锁obj
然后还是按1→2→3→4这么循环下来,那T1,T2,T3应该是没有执行到的机会除非是T0刚好在解锁obj后、未进入下一次循环加锁obj之前,时间片到期,那其他线程才有执行的可能。但是会这么巧,刚好时间片在执行解锁完后到期吗?从实际输出结果看,各个线程都是有执行过一段时间的。不知道哪个地方理解有误,求解多线程时间片线程同步

解决方案 »

  1.   

    别人竞争的时候发现obj被锁了,他也没办法继续向下运行啊
      

  2.   

    Thread.sleep 并不会释放所持有的对象锁,而是堵在那里了。
    锁对象的 wait 方法可以让当前线程阻塞的同时,将对象锁释放掉。
      

  3.   

    这四个线程分别叫T0,T1,T2,T3。在我理解看来:
    1.T0锁定obj后,进入sleep 10ms,将运行权交给T1
    2.T1发现obj被锁后,将运行权交给T2
    3.同理T2交给T3,T3交还T0
    4.此时T0往下运行,输出ticket号,然后解锁obj,由于是while(true),继续循环加锁obj这里给楼主提个问题:
    T0运行完为什么一定是将运行权交给T1?除非是T0刚好在解锁obj后、未进入下一次循环加锁obj之前,时间片到期,那其他线程才有执行的可能。但是会这么巧,刚好时间片在执行解锁完后到期吗?这里也给楼主提个问题:
    在不止一个CPU的情况下,为什么第二个线程一定要等着第一个线程运行完才有CPU资源?楼主去找一个单核的CPU,双核的,4核的都试一下上面的程序,看看结果。
      

  4.   

    嗯啊,我知道不会解锁,只是堵了后交出运行权(单核cpu),那此时别的线程由于未解锁所以无法执行,我记得孙鑫老师执行的结果是每个线程轮流执行一次输出,他应该是单核电脑,04年的视频了,不清楚为什么别的线程也执行了。除非时间片刚好在解锁obj后、未进入下一次循环加锁obj之前这个点切换了。是吗?
      

  5.   


    1.T0到T3的顺序和它start的顺序没关系么?不清楚系统是按什么顺序来调度的,但是和我的问题没多大关系,反正意思是它把运行权交出去了
    2.这里就讨论单核情况哦,多核的我再去看看。孙鑫老师的结果是每个线程按次序执行输出一次,循环到100扣完为止。
      

  6.   

    一句话,Thread.sleep(10);不会释放对象锁.
      

  7.   

    嗯啊,释放对象锁是在synchronized(obj){...}大括号执行完之后,我没理解错吧。
      

  8.   

    其实在同一时间点上,cpu只有一个线程在运行,但是由于它的运算速度太快,所以给我们的感觉是所有线程都在进行。双核或者以上的cpu才能做到真正意义上的多线程。
    所以4楼朋友问得很好。