黑马程序员技术交流社区

标题: 同步函数和同步代码块的切换问题! [打印本页]

作者: yinxjfly    时间: 2014-5-29 17:13
标题: 同步函数和同步代码块的切换问题!
代码如下:
class Ticket implements Runnable
{
        private  int tick = 400;
        Object obj = new Object();
        boolean flag = true;
        public  void run()
        {
                if(flag)
                {
                        while(true)
                        {
                                synchronized(this)
                                {
                                        if(tick>0)
                                        {
                                                //try{Thread.sleep(10);}catch(Exception e){}
                                                System.out.println(Thread.currentThread().getName()+"....code : "+ tick--);
                                        }
                                }
                        }
                }
                else
                        while(true)
                                show();
        }
        public synchronized void show()//this
        {
                if(tick>0)
                {
                        //try{Thread.sleep(10);}catch(Exception e){}
                        System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--);
                }
        }
}
class  ThisLockDemo
{
        public static void main(String[] args)
        {

                Ticket t = new Ticket();

                Thread t1 = new Thread(t);
                Thread t2 = new Thread(t);
                t1.start();//位置1
                try{Thread.sleep(1);}catch(Exception e){}
                t.flag = false;//位置2
                t2.start();

        }
}


问题如下,线程t1开启后(位置1),此时标记位flag为true,所以执行的的是同步代码块中的代码,
随后将Ticket的实例对象t的标记位flag置false(位置2),随后开启t2线程,t2开启后执行同步函数中的代码。
按照代码的执行逻辑来分析,此时标记位是false,两个线程都应该执行的是同步函数中的代码,
但通过实际运行发现(调整主线程休眠时间可以明显发现),在还有余票的前提下,t1还是在执行同步代码块中的内容(问题是此时标记为flag是false)
,并没有因为标记位的改变而执行同步函数中的代码。这是什么原因的?希望高手帮忙解答!!
(其实自己找到了一个自圆其说的答案,只是还不确定)



作者: fenzheng    时间: 2014-5-29 17:23
没有搞明白?你到底想说什么?可以吧你的问题再说一遍吗?
作者: fenzheng    时间: 2014-5-29 17:28
t1在flag=ture的时候执行同步代码块的代码,没有问题,t2在flag=false的时候执行同步函数的问题,没有问题
作者: fenzheng    时间: 2014-5-29 17:29
再还有票的情况下,t1是阻塞的,当然会一直执行啊,你已经在改变flag之前你start()了呀?代码的执行是没有问题的,你想两个都走同步函数,你的start()都必须在改变了flag之后才行
作者: yinxjfly    时间: 2014-5-29 17:30
fenzheng 发表于 2014-5-29 17:23
没有搞明白?你到底想说什么?可以吧你的问题再说一遍吗?

这个问题是有点费脑筋,想了好久才决定发帖的,问题描述写的很清楚了啊!
简单说就是,ticket的类中封装了一个标记位(flag),通过标记为真假值的改变让创建的两个线程去执行标记为所对应区域的代码,但是当标记位被置为假时,线程一还是在执行标记位为真时所对应的代码!
作者: fenzheng    时间: 2014-5-29 17:31
class  ThisLockDemo
{
        public static void main(String[] args)
        {

                Ticket t = new Ticket();

                Thread t1 = new Thread(t);
                Thread t2 = new Thread(t);
                t.flag = false;//位置2
                t1.start();//位置1
                try{Thread.sleep(1);}catch(Exception e){}
                t2.start();

        }
}

这样就可以满足你的要求了,将start()的位置都放到flag改变之后就可以了
作者: fenzheng    时间: 2014-5-29 17:32
老大,你的研究精神值得学习,但是代码的执行就是这样的呀?你那样的想法是不合逻辑的,行不通的
作者: yinxjfly    时间: 2014-5-29 17:38
fenzheng 发表于 2014-5-29 17:32
老大,你的研究精神值得学习,但是代码的执行就是这样的呀?你那样的想法是不合逻辑的,行不通的 ...

你说的没问题,如果只想执行同步函数中的代码,在开启两个线程前将标记为改变就好。
想法得到验证就好,多谢啦!

作者: Alan_Kwan    时间: 2014-5-29 17:50
没看懂你的意思,不过你的同步用得不对,会出问题,你的共享资源是tick,但是你改变tick的地方有两个而只锁了一个,这是问题一。

然后,线程被唤醒的时候,会在之前被中断的位置继续顺序执行。假如当线程1刚刚进入了flag =true的代码块后马上被切换了,然后此时flag被其他线程改成了false,当线程1被唤醒的时候,它还是会在之前被中断的位置顺序执行的。

你把后面相关的视频看了就能理解了。优化方法在后面也有了。
作者: yinxjfly    时间: 2014-5-29 17:55
Alan_Kwan 发表于 2014-5-29 17:50
没看懂你的意思,不过你的同步用得不对,会出问题,你的共享资源是tick,但是你改变tick的地方有两个而只锁 ...

好的!谢谢!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2