⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 如果我是国王:关于解决 java 编程语言线程问题的建议.htm

📁 java的Java书籍JAVA多线程!请大家看看!!有学习的价值!!!xieixe
💻 HTM
📖 第 1 页 / 共 5 页
字号:
              <TBODY>
              <TR>
                <TD><PRE>    static Object global_resource;

    //...

    public void a()
    {
        $reading( global_resource )
        {   // While in this block, other threads requesting read
            // access to global_resource will get it, but threads
            // requesting write access will block.
        }
    }

    public void b()
    {
        $writing( global_resource )
        {   // Blocks until all ongoing read or write operations on
            // global_resource are complete. No read or write
            // operation or global_resource can be initiated while
            // within this block.
        }
    }

    public $reading void c()
    {   // just like $reading(this)...
    }

    public $writing void d()
    {   // just like $writing(this)...
    }
</PRE></TD></TR></TBODY></TABLE>
            <P>对于一个对象,应该只有在 <CODE>$writing</CODE> <CODE></CODE>块中没有线程时,才支持多个线程进入 
            <CODE>$reading</CODE> 块。在进行读操作时,一个试图进入 <CODE>$writing</CODE> 
            块的线程会被阻断,直到读线程退出 <CODE>$reading</CODE> 块。 当有其它线程处于 
            <CODE>$writing</CODE> 块时,试图进入 <CODE>$reading</CODE> 或 
            <CODE>$writing</CODE> 块的线程会被阻断,直到此写线程退出 <CODE>$writing</CODE> 
            <CODE></CODE>块。</P>
            <P>如果读和写线程都在等待,缺省情况下,读线程会首先进行。但是,可以使用 <CODE>$writer_priority</CODE> 
            属性修改类的定义来改变这种缺省方式。如:</P>
            <TABLE class=code-sample cellPadding=0 width="100%" border=0>
              <TBODY>
              <TR>
                <TD><PRE>$write_priority class IO
{   
    $writing write( byte[] data )
    {   //...
    }

    $reading byte[] read( )
    {   //...
    }
}
</PRE></TD></TR></TBODY></TABLE><A id=7 name=7></A>
            <P><STRONG class=subhead>访问部分创建的对象应是非法的</STRONG><BR>当前情况下,JLS 
            允许访问部分创建的对象。例如,在一个构造函数中创建的线程可以访问正被创建的对象,既使此对象没有完全被创建。下面代码的结果无法确定:</P>
            <TABLE class=code-sample cellPadding=0 width="100%" border=0>
              <TBODY>
              <TR>
                <TD><PRE>    class Broken
    {   private long x;

        Broken()
        {   new Thread()
            {   public void run()
                {   x = -1;
                }
            }.start();

            x = 0;
        }
    }
</PRE></TD></TR></TBODY></TABLE>
            <P>设置 <CODE>x</CODE> 为 -1 的线程可以和设置 <CODE>x</CODE> 为 0 的线程同时进行。所以,此时 
            <CODE>x</CODE> 的值无法预测。</P>
            <P>对此问题的一个解决方法是,在构造函数没有返回之前,对于在此构造函数中创建的线程,既使它的优先级比调用 
            <CODE>new</CODE> 的线程高,也要禁止运行它的 <CODE>run()</CODE> 方法。</P>
            <P>这就是说,在构造函数返回之前, <CODE>start()</CODE> 请求必须被推迟。</P>
            <P>另外,Java 编程语言应可允许构造函数的同步。换句话说,下面的代码(在当前情况下是非法的)会象预期的那样工作:</P>
            <P></P>
            <TABLE class=code-sample cellPadding=0 width="100%" border=0>
              <TBODY>
              <TR>
                <TD><PRE>    class Illegal
    {   private long x;

        <B>synchronized</B> Broken()
        {   new Thread()
            {   public void run()
                {   <B>synchronized( Illegal.this )
                    {</B>
                        x = -1;
                    <B>}</B>
                }
            }.start();

            x = 0;
        }
    }
</PRE></TD></TR></TBODY></TABLE>
            <P>我认为第一种方法比第二种更简洁,但实现起来更为困难。</P><A id=7a name=7a></A>
            <P><STRONG class=subhead><CODE>volatile</CODE> 
            关键字应象预期的那样工作</STRONG><BR>JLS 要求保留对于 volatile 操作的请求。大多数 Java 
            虚拟机都简单地忽略了这部分内容,这是不应该的。在多处理器的情况下,许多主机都出现了这种问题,但是它本应由 JLS 
            加以解决的。如果您对这方面感兴趣,马里兰大学的 Bill Pugh 正在致力于这项工作(请参阅<A 
            href="http://www-900.ibm.com/developerWorks/cn/java/j-king/index.shtml#resources">参考资料</A>)。</P><A 
            id=8 name=8></A>
            <P><STRONG 
            class=subhead>访问的问题</STRONG><BR>如果缺少良好的访问控制,会使线程编程非常困难。大多数情况下,如果能保证线程只从同步子系统中调用,不必考虑线程安全(threadsafe)问题。我建议对 
            Java 编程语言的访问权限概念做如下限制;</P>
            <OL>
              <LI>应精确使用 <CODE>package</CODE> 
              关键字来限制包访问权。我认为当缺省行为的存在是任何一种计算机语言的一个瑕疵,我对现在存在这种缺省权限感到很迷惑(而且这种缺省是“包(package)”级别的而不是“私有(private)”)。在其它方面,Java 
              编程语言都不提供等同的缺省关键字。虽然使用显式的 <CODE>package</CODE> 
              的限定词会破坏现有代码,但是它将使代码的可读性更强,并能消除整个类的潜在错误 
              (例如,如果访问权是由于错误被忽略,而不是被故意忽略)。 
              <LI>重新引入 <CODE>private protected</CODE>,它的功能应和现在的 
              <CODE>protected</CODE> 一样,但是不应允许包级别的访问。 
              <LI>允许 <CODE>private private</CODE> 
              语法指定“实现的访问”对于所有外部对象是私有的,甚至是当前对象是的同一个类的。对于“.”左边的唯一引用(隐式或显式)应是 
              <CODE>this</CODE>。 
              <LI>扩展 <CODE>public</CODE> 的语法,以授权它可制定特定类的访问。例如,下面的代码应允许 
              <CODE>Fred</CODE> 类的对象可调用 
              <CODE>some_method()</CODE>,但是对其它类的对象,这个方法应是私有的。 
              <LI style="LIST-STYLE-TYPE: none">
              <TABLE class=code-sample cellPadding=0 width="100%" border=0>
                <TBODY>
                <TR>
                  <TD><PRE>    public(Fred) void some_method()
    {
    }
</PRE></TD></TR></TBODY></TABLE>
              <P>这种建议不同于 C++ 的 "friend" 机制。 在 "friend" 
              机制中,它授权一个类访问另一个类的<I>所有</I>私有部分。在这里,我建议对有限的方法集合进行严格控制的访问。用这种方法,一个类可以为另一个类定义一个接口,而这个接口对系统的其余类是不可见的。一个明显的变化是:</P>
              <TABLE class=code-sample cellPadding=0 width="100%" border=0>
                <TBODY>
                <TR>
                  <TD><PRE>    public(Fred, Wilma) void some_method()
    {
    }
</PRE></TD></TR></TBODY></TABLE>
              <LI>
              <P>除非域引用的是真正不变(immutable)的对象或 <CODE>static final</CODE> 
              基本类型,否则所有域的定义应是 <CODE>private</CODE>。对于一个类中域的直接访问违反了 OO 
              设计的两个基本规则:抽象和封装。从线程的观点来看,允许直接访问域只使对它进行非同步访问更容易一些。</P>
              <LI>
              <P>增加 <CODE>$property</CODE> 关键字。带有此关键字的对象可被一个“bean 
              盒”应用程序访问,这个程序使用在 <CODE>Class</CODE> 类中定义的反射操作(introspection) 
              API,否则与 private private 同效。 <CODE>$property</CODE> 属性可用在域和方法,这样现有的 
              JavaBean getter/setter 方法可以很容易地被定义为属性。</P></LI></OL><A id=9 
            name=9></A>
            <P><B>不变性(immutability)</B><BR>由于对不变对象的访问不需要同步,所以在多线程条件下,不变的概念(一个对象的值在创建后不可更改)是无价的。Java 
            编程言语中,对于不变性的实现不够严格,有两个原因:</P>
            <UL>
              <LI>对于一个不变对象,在其被未完全创建之前,可以对它进行访问。这种访问对于某些域可以产生不正确的值。 
              <LI>对于恒定 (类的所有域都是 <CODE>final)</CODE> 的定义太松散。对于由 
              <CODE>final</CODE> <CODE></CODE>引用指定的对象,虽然引用本身不能改变,但是对象本身可以改变状态。 
              </LI></UL>
            <P>第一个问题可以解决,不允许线程在构造函数中开始执行 (或者在构造函数返回之前不能执行开始请求)。</P>
            <P>对于第二个问题,通过限定 <CODE>final</CODE> 
            修饰符指向恒定对象,可以解决此问题。这就是说,对于一个对象,只有所有的域是 final,并且所有引用的对象的域也都是 
            final,此对象才真正是恒定的。为了不打破现有代码,这个定义可以使用编译器加强,即只有一个类被显式标为不变时,此类才是不变类。方法如下:</P>
            <TABLE class=code-sample cellPadding=0 width="100%" border=0>
              <TBODY>
              <TR>
                <TD><PRE>    <B>$immutable</B> public class Fred
    {   
        // all fields in this class must be final, and if the
        // field is a reference, all fields in the referenced
        // class must be final as well (recursively).

        static int x constant = 0;  // use of `final` is optional when $immutable
                                    // is present.
    }
</PRE></TD></TR></TBODY></TABLE>
            <P>有了 <CODE>$immutable</CODE> 修饰符后,在域定义中的 <CODE>final</CODE> 
            修饰符是可选的。</P>
            <P>最后,当使用内部类(inner class)后,在 Java 
            编译器中的一个错误使它无法可靠地创建不变对象。当一个类有重要的内部类时(我的代码常有),编译器经常不正确地显示下列错误信息:</P>
            <TABLE class=code-sample cellPadding=0 width="100%" border=0>
              <TBODY>
              <TR>
                <TD><PRE>"Blank final variable '<I>name</I>' may not have been initialized.
It must be assigned a value in an initializer, or in every constructor."
</PRE></TD></TR></TBODY></TABLE>
            <P>既使空的 final 在每个构造函数中都有初始化,还是会出现这个错误信息。自从在 1.1 
            版本中引入内部类后,编译器中一直有这个错误。在此版本中(三年以后),这个错误依然存在。现在,该是改正这个错误的时候了。</P><A 
            id=10 name=10></A>
            <P><B>对于类级域的实例级访问</B><BR>除了访问权限外,还有一个问题

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -