📄 tij0156.html
字号:
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>TwoCounter</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
objects.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Sharing1</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
contains an array of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>TwoCounter</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
objects that it initializes in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>init( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and starts as threads when you press the “start” button. Later,
when you press the “Observe” button, one or more observers are
created and freed upon the unsuspecting
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>TwoCounter
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">threads.</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Note
that to run this as an applet in a browser, your Web page will need to contain
the lines:
</FONT><P></DIV>
<font color="#990000"><PRE><applet code=Sharing1 width=650 height=500>
<param name=size value="20">
<param name=observers value="1">
</applet></PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You
can change the width, height, and parameters to suit your experimental tastes.
By changing the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>size</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>observers</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
you’ll change the behavior of the program. You can also see that this
program is set up to run as a stand-alone application by pulling the arguments
from the command line (or providing defaults).
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Here’s
the surprising part. In
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>TwoCounter.run( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
the infinite loop is just repeatedly passing over the adjacent lines:
</FONT><P></DIV>
<font color="#990000"><PRE>t1.setText(Integer.toString(count1++));
t2.setText(Integer.toString(count2++));</PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">(as
well as sleeping, but that’s not important here). When you run the
program, however, you’ll discover that
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>count1</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>count2</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
will be observed (by the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Watcher</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)
to be unequal at times! This is because of the nature of threads – they
can be <A NAME="Index2492"></A>suspended
at any time. So at times, the suspension occurs
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>between</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
the execution of the above two lines, and the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Watcher</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
thread happens to come along and perform the comparison at just this moment,
thus finding the two counters to be different.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
example shows a fundamental problem with using threads. You never know when a
thread might be run. Imagine sitting at a table with a fork, about to spear the
last piece of food on your plate and as your fork reaches for it, the food
suddenly vanishes (because your thread was suspended and another thread came in
and stole the food). That’s the problem that you’re dealing with.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Sometimes
you don’t care if a resource is being accessed at the same time
you’re trying to use it (the food is on some other plate). But for
multithreading to work, you need some way to prevent two threads from accessing
the same resource, at least during critical periods.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Preventing
this kind of collision is simply a matter of putting a lock on a resource when
one thread is using it. The first thread that accesses a resource locks it, and
then the other threads cannot access that resource until it is unlocked, at
which time another thread locks and uses it, etc. If the front seat of the car
is the limited resource, the child who shouts “Dibs!” asserts the
lock.
</FONT><a name="_Toc375545480"></a><a name="_Toc408018753"></a><P></DIV>
<A NAME="Heading491"></A><H3 ALIGN=LEFT>
How
Java shares resources
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Java
has built-in support to prevent collisions over one kind of resource: the
memory in an object. Since you typically make the data elements of a class <A NAME="Index2493"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>private</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and access that memory only through methods, you can prevent collisions by
making a particular method <A NAME="Index2494"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
Only one thread at a time can call a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method for a particular object (although that thread can call more than one of
the object’s synchronized methods). Here are simple
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
methods:
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#0000ff">synchronized</font> <font color="#0000ff">void</font> f() { <font color="#009900">/* ... */</font> }
<font color="#0000ff">synchronized</font> <font color="#0000ff">void</font> g(){ <font color="#009900">/* ... */</font> } </PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Each
object contains a single <A NAME="Index2495"></A><A NAME="Index2496"></A>lock
(also called a <A NAME="Index2497"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>monitor</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)
that is automatically part of the object (you don’t have to write any
special code). When you call any
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method, that object is locked and no other
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method of that object can be called until the first one finishes and releases
the lock. In the example above, if
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>f( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is called for an object,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>g( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
cannot be called for the same object until
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>f( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is completed and releases the lock. Thus, there’s a single lock
that’s shared by all the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
methods of a particular object, and this lock prevents common memory from being
written by more than one method at a time (i.e. more than one thread at a time).
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">There’s
also a single lock per class (as part of the <A NAME="Index2498"></A><A NAME="Index2499"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Class</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object for the class), so that <A NAME="Index2500"></A><A NAME="Index2501"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>static</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
methods can lock each other out from
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>static
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">data
on a class-wide basis.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Note
that if you want to guard some other resource from simultaneous access by
multiple threads, you can do so by forcing access to that resource through
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
methods.
</FONT><P></DIV>
<A NAME="Heading492"></A><H4 ALIGN=LEFT>
Synchronizing
the counters
</H4>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Armed
with this new keyword it appears that the solution is at hand: we’ll
simply use the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
keyword for the methods in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>TwoCounter</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
The following example is the same as the previous one, with the addition of the
new keyword:
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: Sharing2.java</font>
<font color="#009900">// Using the synchronized keyword to prevent</font>
<font color="#009900">// multiple access to a particular resource.</font>
<font color="#0000ff">import</font> java.awt.*;
<font color="#0000ff">import</font> java.awt.event.*;
<font color="#0000ff">import</font> java.applet.*;
<font color="#0000ff">class</font> TwoCounter2 <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> TextField
t1 = <font color="#0000ff">new</font> TextField(5),
t2 = <font color="#0000ff">new</font> TextField(5);
<font color="#0000ff">private</font> Label l =
<font color="#0000ff">new</font> Label("count1 == count2");
<font color="#0000ff">private</font> <font color="#0000ff">int</font> count1 = 0, count2 = 0;
<font color="#0000ff">public</font> TwoCounter2(Container c) {
Panel p = <font color="#0000ff">new</font> Panel();
p.add(t1);
p.add(t2);
p.add(l);
c.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">synchronized</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){}
}
}
<font color="#0000ff">public</font> <font color="#0000ff">synchronized</font> <font color="#0000ff">void</font> synchTest() {
Sharing2.incrementAccess();
<font color="#0000ff">if</font>(count1 != count2)
l.setText("Unsynched");
}
}
<font color="#0000ff">class</font> Watcher2 <font color="#0000ff">extends</font> Thread {
<font color="#0000ff">private</font> Sharing2 p;
<font color="#0000ff">public</font> Watcher2(Sharing2 p) {
<font color="#0000ff">this</font>.p = p;
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 < p.s.length; i++)
p.s[i].synchTest();
<font color="#0000ff">try</font> {
sleep(500);
} <font color="#0000ff">catch</font> (InterruptedException e){}
}
}
}
<font color="#0000ff">public</font> <font color="#0000ff">class</font> Sharing2 <font color="#0000ff">extends</font> Applet {
TwoCounter2[] s;
<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> TextField aCount =
<font color="#0000ff">new</font> TextField("0", 10);
<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> Button
start = <font color="#0000ff">new</font> Button("Start"),
observer = <font color="#0000ff">new</font> Button("Observe");
<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 = 0;
<font color="#0000ff">private</font> <font color="#0000ff">int</font> numObservers = 0;
<font color="#0000ff">public</font> <font color="#0000ff">void</font> init() {
<font color="#0000ff">if</font>(isApplet) {
numCounters =
Integer.parseInt(getParameter("size"));
numObservers =
Integer.parseInt(
getParameter("observers"));
}
s = <font color="#0000ff">new</font> TwoCounter2[numCounters];
<font color="#0000ff">for</font>(<font color="#0000ff">int</font> i = 0; i < s.length; i++)
s[i] = <font color="#0000ff">new</font> TwoCounter2(<font color="#0000ff">this</font>);
Panel p = <font color="#0000ff">new</font> Panel();
start.addActionListener(<font color="#0000ff">new</font> StartL());
p.add(start);
observer.addActionListener(<font color="#0000ff">new</font> ObserverL());
p.add(observer);
p.add(<font color="#0000ff">new</font> Label("Access Count"));
p.add(aCount);
add(p);
}
<font color="#0000ff">class</font> StartL <font color="#0000ff">implements</font> ActionListener {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -