A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© yinxjfly 高级黑马   /  2014-5-29 17:13  /  1940 人查看  /  9 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

代码如下:
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)
,并没有因为标记位的改变而执行同步函数中的代码。这是什么原因的?希望高手帮忙解答!!
(其实自己找到了一个自圆其说的答案,只是还不确定)


评分

参与人数 1技术分 +1 收起 理由
李小然 + 1

查看全部评分

9 个回复

倒序浏览
没有搞明白?你到底想说什么?可以吧你的问题再说一遍吗?
回复 使用道具 举报
t1在flag=ture的时候执行同步代码块的代码,没有问题,t2在flag=false的时候执行同步函数的问题,没有问题
回复 使用道具 举报
再还有票的情况下,t1是阻塞的,当然会一直执行啊,你已经在改变flag之前你start()了呀?代码的执行是没有问题的,你想两个都走同步函数,你的start()都必须在改变了flag之后才行

评分

参与人数 1技术分 +1 收起 理由
李小然 + 1 赞一个!

查看全部评分

回复 使用道具 举报
fenzheng 发表于 2014-5-29 17:23
没有搞明白?你到底想说什么?可以吧你的问题再说一遍吗?

这个问题是有点费脑筋,想了好久才决定发帖的,问题描述写的很清楚了啊!
简单说就是,ticket的类中封装了一个标记位(flag),通过标记为真假值的改变让创建的两个线程去执行标记为所对应区域的代码,但是当标记位被置为假时,线程一还是在执行标记位为真时所对应的代码!
回复 使用道具 举报
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
老大,你的研究精神值得学习,但是代码的执行就是这样的呀?你那样的想法是不合逻辑的,行不通的 ...

你说的没问题,如果只想执行同步函数中的代码,在开启两个线程前将标记为改变就好。
想法得到验证就好,多谢啦!
回复 使用道具 举报
没看懂你的意思,不过你的同步用得不对,会出问题,你的共享资源是tick,但是你改变tick的地方有两个而只锁了一个,这是问题一。

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

你把后面相关的视频看了就能理解了。优化方法在后面也有了。

评分

参与人数 1技术分 +1 收起 理由
李小然 + 1 赞一个!

查看全部评分

回复 使用道具 举报
Alan_Kwan 发表于 2014-5-29 17:50
没看懂你的意思,不过你的同步用得不对,会出问题,你的共享资源是tick,但是你改变tick的地方有两个而只锁 ...

好的!谢谢!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马