免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1569 | 回复: 3
打印 上一主题 下一主题

求助:百思不得其解的线程突变。 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-06-10 17:15 |只看该作者 |倒序浏览
实现一个功能打印 "12 a 34 b 56 c ................"一直打到字母z。
利用两个线程t1 和 t2来实现。它们共同控制ThreadNL 的资源。利用synchronized方法实现两个线程对同一个资源的交替访问。程序先让t1拿到 ThreadNL资源的标记锁(这时候t2因为没有标记锁则进入锁池),等到t1执行完后,再扔出标记锁,然后自己进入锁池队列,让t2在锁池中看到标记锁后,CPU就有很大的可能把标记锁给t2。这样它们就可以进行同步地访问了。然而CPU时间好做怪啊,觉得以下的例子1,比例子2应该更稳定不容易引发线程突变。可是偏偏~~~~
例子1
import java.util.*;
import java.lang.*;
public class TestNum_Let
{
        public static void main(String []args)
        {
                ThreadNL tnl=new ThreadNL(); //共用的资源
               
               
               
               
                Runnable r1=new Num(tnl);
                Runnable r2=new Let(tnl);
               
                Thread t1=new Thread(r1);
                Thread t2=new Thread(r2);
               
               
               
                t1.start();
                t2.start();
        }
}
class Num implements Runnable
{
       
        private ThreadNL s1;
       
        public Num(ThreadNL s)
        {
                this.s1=s;             //通过参数传递共用一个资源
        }
        public void run()
        {
           for(int i=1;i<=52;i++)
          {  
                   
                           
                                               
                 synchronized(s1)    //互斥访问
                {
               
                  if(i%2==0)
                      s1.printNum(i);
                   
                }            
       
          }
   }
}       
class Let implements Runnable
{
       
        private ThreadNL s2;
        public Let(ThreadNL s)
        {
                this.s2=s;
        }
       
        public void run()
        {
                for(char c='a';c<='z';c++)
                {
                       
                        synchronized(s2)
                        {
                       
                              s2.printLet(c);
                        }
                       
                       
                }
               
        }
               
}
class ThreadNL
{
        public void printNum(int i)
        {
                System.out.println(i-1+""+i);
                        try
                   { Thread.sleep(20);}
                  catch(InterruptedException e)
                  {e.printStackTrace();}
        }
        public void printLet(char c)
        {
                System.out.println(c);
                 try
                      {Thread.sleep(100);}
                         catch(InterruptedException e)
                      {e.printStackTrace();}
        }
}


输出:
12
a
b
34
c
d
56
e
78
f
g
910
h
1112
i
j
1314
k
1516
l
m
1718
n
1920
o
p
2122
q
r
2324
s
t
2526
u
v
2728
w
2930
x
y
3132
z
3334
3536
3738
3940
4142
4344
4546
4748
4950
5152



如果我把上面的程序,只是改动一行的话就严格按照我的要求打印了,好奇怪啊~~

public class TestNum_Let
{
        public static void main(String []args)
        {
                ThreadNL tnl=new ThreadNL();
               
               
               
               
                Runnable r1=new Num(tnl);
                Runnable r2=new Let(tnl);
               
                Thread t1=new Thread(r1);
                Thread t2=new Thread(r2);
               
               
               
                t1.start();
                t2.start();
        }
}
class Num implements Runnable
{
       
       private ThreadNL s1;
       
               public Num(ThreadNL s)
        {
                this.s1=s;
        }
        public void run()
        {
           for(int i=1;i<=52;i++)
          {  
                   
       
               if(i%2==0)      //只是改动了这行,把if语句包在synchronized外面                   
               { //if 语句开始
                            synchronized(s1)
                  {
               
                  
                      s1.printNum(i);
                   
                }
              } //if语句结束
                       
          }
   }
}       
class Let implements Runnable
{
       
        private ThreadNL s2;
        public Let(ThreadNL s)
        {
                this.s2=s;
        }
       
        public void run()
        {
                for(char c='a';c<='z';c++)
                {
                       
                        synchronized(s2)
                        {
                       
                              s2.printLet(c);
                        }
                       
                       
                }
               
        }
               
}
class ThreadNL
{
        public void printNum(int i)
        {
                System.out.println(i-1+""+i);
                        try
                   { Thread.sleep(20);}
                  catch(InterruptedException e)
                  {e.printStackTrace();}
        }
        public void printLet(char c)
        {
                System.out.println(c);
                         try
                         {Thread.sleep(100);}
                         catch(InterruptedException e)
                         {e.printStackTrace();}
        }
}
输出
12
a
34
b
56
c
78
d
910
e
1112
f
1314
g
1516
h
1718
i
1920
j
2122
k
2324
l
2526
m
2728
n
2930
o
3132
p
3334
q
3536
r
3738
s
3940
t
4142
u
4344
v
4546
w
4748
x
4950
y
5152
z




问题:例子2的if先判断,而例子1的if在synchronized里面才判断,按理来说,例子2 中假设i=1的时候,i++还没有执行完的时候,t1线程的时间片就有可能给用完了,接着就到了t2运行了,这时就发生了突变,而例子1的for循环里就是一个synchronized,在里面运行的代码应该不可能发生突变的。但偏偏就发生了,为什么会如常啊? 为什么例子2比例子1更安全啊? 请各位大虾指教,万分感谢!

论坛徽章:
0
2 [报告]
发表于 2006-06-10 20:45 |只看该作者
我对线程也不熟悉但是你现在的写发不对 。
起码我在linux上跑的结果都不对

论坛徽章:
0
3 [报告]
发表于 2006-06-11 16:46 |只看该作者
你的程序实际执行就是看那个线程先抢到资源,你所说的稳定只是你机器上的当时的现象
"程序先让t1拿到 ThreadNL资源的标记锁",只是你认为先启动线程t1的结论

论坛徽章:
0
4 [报告]
发表于 2006-06-13 03:36 |只看该作者
当你两个线程运行条件相等的时候,没有任何保证其中一个线程的执行速度一定比另一个快。因此,当你的Let和Num都拥有一样的条件--在循环里面synchronized的时候,没有保证哪一个线程的循环运行速度一定优先或者相等。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP