zoukankan      html  css  js  c++  java
  • 谜题76: 乒乓

    下面的程序全部是由同步化(synchronized)的静态方法组成的。那么它会打印
    出什么呢?在你每次运行这段程序的时候,它都能保证会打印出相同的内容吗?

    public class PingPong{
    public static synchronized void main(String[] a){
    Thread t = new Thread(){
    public void run(){ pong(); }
    };
    t.run();
    System.out.print( "Ping" );
    }
    static synchronized void pong(){
    System.out.print( "Pong" );
    }
    }
    

      


    在多线程程序中,通常正确的观点是程序每次运行的结果都有可能发生变化,但
    是上面这段程序总是打印出相同的内容。在一个同步化的静态方法执行之前,它
    会获取与它的 Class 对象相关联的一个管程(monitor)锁[JLS 8.4.3.6]。所以
    在上面的程序中,主线程会在创建第二个线程之前获得与 PingPong.class 相关
    联的那个锁。只要主线程占有着这个锁,第二个线程就不可能执行同步化的静态
    方法。具体地讲,在 main 方法打印了 Ping 并且执行结束之后,第二个线程才能
    执行 pong 方法。只有当主线程放弃那个锁的时候,第二个线程才被允许获得这
    个锁并且打印 Pong 。根据以上的分析,我们似乎可以确信这个程序应该总是打

    印 PingPong。但是这里有一个小问题:当你尝试着运行这个程序的时候,你会
    发现它总是会打印 PongPing。到底发生了什么呢?
    正如它看起来的那样奇怪,这段程序并不是一个多线程程序。不是一个多线程程
    序?怎么可能呢?它肯定会生成第二个线程啊。喔,对的,它确实是创建了第二
    个线程,但是它从未启动这个线程。相反地,主线程会调用那个新的线程实例的
    run 方法,这个 run 方法会在主线程中同步地运行。由于一个线程可以重复地获
    得某个相同的锁 [JLS 17.1] ,所以当 run 方法调用 pong 方法的时候,主线程
    就被允许再次获得与 PingPong.class 相关联的锁。pong 方法打印了 Pong 并且
    返回到了 run方法,而 run方法又返回到 main方法。最后,main方法打印了 Ping,
    这就解释了我们看到的输出结果是怎么来的。
    要订正这个程序很简单,只需将 t.run 改写成 t.start。这么做之后,这个程
    序就会如你所愿的总是打印出 PingPong 了。
    这个教训很简单:当你想调用一个线程的 start 方法时要多加小心,别弄错成调
    用这个线程的 run 方法了。遗憾的是,这个错误实在是太普遍了,而且它可能很
    难被发现。或许这个谜题的教训应该是针对 API 的设计者的:如果一个线程没有
    一个公共的 run 方法,那么程序员就不可能意外地调用到它。Thread 类之所以
    有一个公共的 run 方法,是因为它实现了 Runnable 接口,但是这种方式并不是
    必须的。另外一种可选的设计方案是:使用组合(composition)来替代接口继
    承(interface inheritance),让每个 Thread 实例都封装一个 Runnable。正如
    谜题 47 中所讨论的,组合通常比继承更可取。这个谜题说明了上述的原则甚至
    对于接口继承也是适用的。

  • 相关阅读:
    Java 第十一届 蓝桥杯 省模拟赛 洁净数
    Java 第十一届 蓝桥杯 省模拟赛 第十层的二叉树
    Java 第十一届 蓝桥杯 省模拟赛 第十层的二叉树
    Java 第十一届 蓝桥杯 省模拟赛 第十层的二叉树
    Java 第十一届 蓝桥杯 省模拟赛 70044与113148的最大公约数
    Java 第十一届 蓝桥杯 省模拟赛 70044与113148的最大公约数
    20. Valid Parentheses
    290. Word Pattern
    205. Isomorphic Strings
    71. Simplify Path
  • 原文地址:https://www.cnblogs.com/yuyu666/p/9841022.html
Copyright © 2011-2022 走看看