chap14.htm

来自「Thinking in Java, 2nd edition」· HTM 代码 · 共 1,236 行 · 第 1/5 页

HTM
1,236
字号

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I38' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER14_I39>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There&#8217;s nothing to keep the program
from terminating once <B>main(&#160;)</B> finishes its job, since there are
nothing but daemon threads running. So that you can see the results of starting
all the daemon threads, <B>System.in</B> is set up to read so the program waits
for a keypress before terminating. Without this you see only some of the results
from the creation of the daemon threads. (Try replacing the <B>read(&#160;)</B>
code with <B>sleep(&#160;)</B> calls of various lengths to see this behavior.)

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I39' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER14_I40>
</FONT><A NAME="_Toc375545478"></A><A NAME="_Toc481064852"></A><BR></P></DIV>
<A NAME="Heading487"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Sharing limited resources<BR><A NAME="Index1925"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can think of a single-threaded
program as one lonely entity moving around through your problem space and doing
one thing at a time. Because there&#8217;s only one entity, you never have to
think about the problem of two entities trying to use the same resource at the
same time, like two people trying to park in the same space, walk through a door
at the same time, or even talk at the same time.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I40' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER14_I41>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">With multithreading, things aren&#8217;t
lonely anymore, but you now have the possibility of two or more threads trying
to use the same limited resource at once. Colliding over a resource must be
prevented or else you&#8217;ll have two threads trying to access the same bank
account at the same time, print to the same printer, or adjust the same valve,
etc.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I41' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER14_I42>
</FONT><A NAME="_Toc375545479"></A><A NAME="_Toc481064853"></A><BR></P></DIV>
<A NAME="Heading488"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Improperly accessing resources</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Consider a variation on the counters that
have been used so far in this chapter. In the following example, each thread
contains two counters that are incremented and displayed inside
<B>run(&#160;)</B>. In addition, there&#8217;s another thread of class
<B>Watcher</B> that is watching the counters to see if they&#8217;re always
equivalent. This seems like a needless activity, since looking at the code it
appears obvious that the counters will always be the same. But that&#8217;s
where the surprise comes in. Here&#8217;s the first version of the
program:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c14:Sharing1.java</font>
<font color=#009900>// Problems with resource sharing while threading.</font>
<font color=#009900>// &lt;applet code=Sharing1 width=350 height=500&gt;</font>
<font color=#009900>// &lt;param name=size value="12"&gt;</font>
<font color=#009900>// &lt;param name=watchers value="15"&gt;</font>
<font color=#009900>// &lt;/applet&gt;</font>
<font color=#0000ff>import</font> javax.swing.*;
<font color=#0000ff>import</font> java.awt.*;
<font color=#0000ff>import</font> java.awt.event.*;
<font color=#0000ff>import</font> com.bruceeckel.swing.*;

<font color=#0000ff>public</font> <font color=#0000ff>class</font> Sharing1 <font color=#0000ff>extends</font> JApplet {
  <font color=#0000ff>private</font> <font color=#0000ff>static</font> <font color=#0000ff>int</font> accessCount = 0;
  <font color=#0000ff>private</font> <font color=#0000ff>static</font> JTextField aCount = 
    <font color=#0000ff>new</font> JTextField(<font color=#004488>"0"</font>, 7);
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> incrementAccess() {
    accessCount++;
    aCount.setText(Integer.toString(accessCount));
  }
  <font color=#0000ff>private</font> JButton 
    start = <font color=#0000ff>new</font> JButton(<font color=#004488>"Start"</font>),
    watcher = <font color=#0000ff>new</font> JButton(<font color=#004488>"Watch"</font>);
  <font color=#0000ff>private</font> <font color=#0000ff>boolean</font> isApplet = <font color=#0000ff>true</font>;
  <font color=#0000ff>private</font> <font color=#0000ff>int</font> numCounters = 12;
  <font color=#0000ff>private</font> <font color=#0000ff>int</font> numWatchers = 15;
  <font color=#0000ff>private</font> TwoCounter[] s;
  <font color=#0000ff>class</font> TwoCounter <font color=#0000ff>extends</font> Thread {
    <font color=#0000ff>private</font> <font color=#0000ff>boolean</font> started = <font color=#0000ff>false</font>;
    <font color=#0000ff>private</font> JTextField 
      t1 = <font color=#0000ff>new</font> JTextField(5),
      t2 = <font color=#0000ff>new</font> JTextField(5);
    <font color=#0000ff>private</font> JLabel l = 
      <font color=#0000ff>new</font> JLabel(<font color=#004488>"count1 == count2"</font>);
    <font color=#0000ff>private</font> <font color=#0000ff>int</font> count1 = 0, count2 = 0;
    <font color=#009900>// Add the display components as a panel:</font>
    <font color=#0000ff>public</font> TwoCounter() {
      JPanel p = <font color=#0000ff>new</font> JPanel();
      p.add(t1);
      p.add(t2);
      p.add(l);
      getContentPane().add(p);
    }
    <font color=#0000ff>public</font> <font color=#0000ff>void</font> start() {
      <font color=#0000ff>if</font>(!started) {
        started = <font color=#0000ff>true</font>;
        <font color=#0000ff>super</font>.start();
      }
    }
    <font color=#0000ff>public</font> <font color=#0000ff>void</font> run() {
      <font color=#0000ff>while</font> (<font color=#0000ff>true</font>) {
        t1.setText(Integer.toString(count1++));
        t2.setText(Integer.toString(count2++));
        <font color=#0000ff>try</font> {
          sleep(500);
        } <font color=#0000ff>catch</font>(InterruptedException e) {
          System.err.println(<font color=#004488>"Interrupted"</font>);
        }
      }
    }
    <font color=#0000ff>public</font> <font color=#0000ff>void</font> synchTest() {
      incrementAccess();
      <font color=#0000ff>if</font>(count1 != count2)
        l.setText(<font color=#004488>"Unsynched"</font>);
    }
  }
  <font color=#0000ff>class</font> Watcher <font color=#0000ff>extends</font> Thread {
    <font color=#0000ff>public</font> Watcher() { start(); }
    <font color=#0000ff>public</font> <font color=#0000ff>void</font> run() {
      <font color=#0000ff>while</font>(<font color=#0000ff>true</font>) {
        <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; s.length; i++)
          s[i].synchTest();
        <font color=#0000ff>try</font> {
          sleep(500);
        } <font color=#0000ff>catch</font>(InterruptedException e) {
          System.err.println(<font color=#004488>"Interrupted"</font>);
        }
      }
    }
  }
  <font color=#0000ff>class</font> StartL <font color=#0000ff>implements</font> ActionListener {
    <font color=#0000ff>public</font> <font color=#0000ff>void</font> actionPerformed(ActionEvent e) {
      <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; s.length; i++)
        s[i].start();
    }
  }
  <font color=#0000ff>class</font> WatcherL <font color=#0000ff>implements</font> ActionListener {
    <font color=#0000ff>public</font> <font color=#0000ff>void</font> actionPerformed(ActionEvent e) {
      <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; numWatchers; i++)
        <font color=#0000ff>new</font> Watcher();
    }
  }
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> init() {
    <font color=#0000ff>if</font>(isApplet) {
      String counters = getParameter(<font color=#004488>"size"</font>);
      <font color=#0000ff>if</font>(counters != <font color=#0000ff>null</font>)
        numCounters = Integer.parseInt(counters);
      String watchers = getParameter(<font color=#004488>"watchers"</font>);
      <font color=#0000ff>if</font>(watchers != <font color=#0000ff>null</font>)
        numWatchers = Integer.parseInt(watchers);
    }
    s = <font color=#0000ff>new</font> TwoCounter[numCounters];
    Container cp = getContentPane();
    cp.setLayout(<font color=#0000ff>new</font> FlowLayout());
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; s.length; i++)
      s[i] = <font color=#0000ff>new</font> TwoCounter();
    JPanel p = <font color=#0000ff>new</font> JPanel();
    start.addActionListener(<font color=#0000ff>new</font> StartL());
    p.add(start);
    watcher.addActionListener(<font color=#0000ff>new</font> WatcherL());
    p.add(watcher);
    p.add(<font color=#0000ff>new</font> JLabel(<font color=#004488>"Access Count"</font>));
    p.add(aCount);
    cp.add(p);
  }
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
    Sharing1 applet = <font color=#0000ff>new</font> Sharing1();
    <font color=#009900>// This isn't an applet, so set the flag and</font>
    <font color=#009900>// produce the parameter values from args:</font>
    applet.isApplet = <font color=#0000ff>false</font>;
    applet.numCounters = 
      (args.length == 0 ? 12 :
        Integer.parseInt(args[0]));
    applet.numWatchers =
      (args.length &lt; 2 ? 15 :
        Integer.parseInt(args[1]));
    Console.run(applet, 350, 
      applet.numCounters * 50);
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As before, each counter contains its own
display components: two text fields and a label that initially indicates that
the counts are equivalent. These components are added to the content pane of the
outer class object in the <B>TwoCounter</B> constructor. 

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I42' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER14_I43>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because a <B>TwoCounter </B>thread is
started via a keypress by the user, it&#8217;s possible that
<B>start(&#160;)</B> could be called more than once. It&#8217;s illegal for
<B>Thread.start(&#160;)</B> to be called more than once for a thread (an
exception is thrown). You can see the machinery to prevent this in the
<B>started </B>flag and the overridden <B>start(&#160;)</B> method.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I43' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER14_I44>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>run(&#160;)</B>, <B>count1</B> and
<B>count2</B> are incremented and displayed in a manner that would seem to keep
them identical. Then
<A NAME="Index1926"></A><A NAME="Index1927"></A><B>sleep(&#160;)</B> is called;
without this call the program balks because it becomes hard for the CPU to swap
tasks. 
</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I44' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER14_I45>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>synchTest(&#160;)</B> method
performs the apparently useless activity of checking to see if <B>count1</B> is
equivalent to <B>count2</B>; if they are not equivalent it sets the label to
&#8220;Unsynched&#8221; to indicate this. But first, it calls a static member of
the class <B>Sharing1</B> that increments and displays an access counter to show
how many times this check has occurred successfully. (The reason for this will
become apparent in later variations of this example.)

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I45' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER14_I46>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>Watcher</B> class is a thread
whose job is to call <B>synchTest(&#160;)</B> for all of the <B>TwoCounter</B>
objects that are active. It does this by stepping through the array that&#8217;s
kept in the <B>Sharing1</B> object. You can think o

⌨️ 快捷键说明

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