📄 tij0156.html
字号:
<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 < s.length; i++)
s[i].start();
}
}
<font color="#0000ff">class</font> ObserverL <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 < numObservers; i++)
<font color="#0000ff">new</font> Watcher2(Sharing2.<font color="#0000ff">this</font>);
}
}
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
Sharing2 applet = <font color="#0000ff">new</font> Sharing2();
<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 ? 5 :
Integer.parseInt(args[0]));
applet.numObservers =
(args.length < 2 ? 5 :
Integer.parseInt(args[1]));
Frame aFrame = <font color="#0000ff">new</font> Frame("Sharing2");
aFrame.addWindowListener(
<font color="#0000ff">new</font> WindowAdapter() {
<font color="#0000ff">public</font> <font color="#0000ff">void</font> windowClosing(WindowEvent e){
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(350, applet.numCounters *100);
applet.init();
applet.start();
aFrame.setVisible(<font color="#0000ff">true</font>);
}
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You’ll
notice that
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>both</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchTest( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
are
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
If you synchronize only one of the methods, then the other is free to ignore
the object lock and can be called with impunity. This is an important point:
Every method that accesses a critical shared resource must be
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
or it won’t work right.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Now
a new issue arises. The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Watcher2</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
can never get a peek at what’s going on because the entire
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method has been
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and since
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is always running for each object the lock is always tied up and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchTest( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
can never be called. You can see this because the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>accessCount</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
never changes.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">What
we’d like for this example is a way to isolate only
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>part</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
of the code inside
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
The section of code you want to isolate this way is called a <A NAME="Index2502"></A><A NAME="Index2503"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>critical
section
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and you 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 in a different way to set up a critical section. Java supports critical
sections with the <A NAME="Index2504"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>synchronized
block;
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
this time
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">is
used to specify the object whose lock is being used to synchronize the enclosed
code:
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#0000ff">synchronized</font>(syncObject) {
<font color="#009900">// This code can be accessed by only</font>
<font color="#009900">// one thread at a time, assuming all</font>
<font color="#009900">// threads respect syncObject's lock</font>
}</PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Before
the synchronized block can be entered, the lock must be acquired on
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>syncObject</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
If some other thread already has this lock, then the block cannot be entered
until the lock is given up.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Sharing2</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
example can be modified by removing 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 from the entire
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method and instead putting a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
block around the two critical lines. But what object should be used as the
lock? The one that is already respected by
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchTest( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
which is the current object (
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>this</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)!
So the modified
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
looks like this:
</FONT><P></DIV>
<font color="#990000"><PRE> <font color="#0000ff">public</font> <font color="#0000ff">void</font> run() {
<font color="#0000ff">while</font> (<font color="#0000ff">true</font>) {
<font color="#0000ff">synchronized</font>(<font color="#0000ff">this</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){}
}
} </PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
is the only change that must be made to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Sharing2.java</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and you’ll see that while the two counters are never out of synch
(according to when the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Watcher</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is allowed to look at them), there is still adequate access provided to the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Watcher</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
during the execution of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Of
course, all synchronization depends on programmer diligence: every piece of
code that can access a shared resource must be wrapped in an appropriate
synchronized block.
</FONT><P></DIV>
<A NAME="Heading493"></A><H4 ALIGN=LEFT>
Synchronized
efficiency
<P><A NAME="Index2505"></A><A NAME="Index2506"></A></H4>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Since
having two methods write to the same piece of data
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>never
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">sounds
like a particularly good idea, it might seem to make sense for all methods to
be automatically
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and eliminate 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 altogether. (Of course, the example with a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized
run( )
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
shows that this wouldn’t work either.) But it turns out that acquiring a
lock is not a cheap operation – it multiplies the cost of a method call
(that is, entering and exiting from the method, not executing the body of the
method) by a minimum of four times, and could be more depending on your
implementation. So if you know that a particular method will not cause
contention problems it is expedient to leave off 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.
</FONT><a name="_Toc408018754"></a><P></DIV>
<A NAME="Heading494"></A><H3 ALIGN=LEFT>
Java
Beans revisited
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Now
that you understand synchronization you can take another look at <A NAME="Index2507"></A><A NAME="Index2508"></A><A NAME="Index2509"></A>Java
Beans. Whenever you create a Bean, you must assume that it will run in a
multithreaded environment. This means that:
</FONT><P></DIV>
<OL>
<LI><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"> Whenever
possible, all the public methods of a Bean should be
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
Of course, this incurs the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
runtime overhead. If that’s a problem, methods that will not cause
problems in critical sections can be left un-
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
but keep in mind that this is not always obvious. Methods that qualify tend to
be small (such as
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>getCircleSize( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in the following example) and/or “atomic,” that is, the method call
executes in such a short amount of code that the object cannot be changed
during execution. Making such methods un-
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">might
not have a significant effect on the execution speed of your program. You might
as well make all
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
methods of a Bean
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>synchronized</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and remove 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 only when you know for sure that it’s necessary and that it makes
a difference.
</FONT><LI><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"> When
firing a <A NAME="Index2510"></A><A NAME="Index2511"></A>multicast
event to a bunch of listeners interested in that event, you must assume that
listeners might be added or removed while moving through the list.
</FONT></OL><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
first point is fairly easy to deal with, but the second point requires a little
more thought. Consider the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>BangBean.java</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
example presented in the last chapter. That ducked out of the multithreading
question by ignoring 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 (which hadn’t been introduced yet) and making the event unicast.
Here’s that example modified to work in a multithreaded environment and
to use multicasting for events:
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: BangBean2.java</font>
<font color="#009900">// You should write your Beans this way so they </font>
<font color="#009900">// can run in a multithreaded environment.</font>
<font color="#0000ff">import</font> java.awt.*;
<font color="#0000ff">import</font> java.awt.event.*;
<font color="#0000ff">import</font> java.util.*;
<font color="#0000ff">import</font> java.io.*;
<font color="#0000ff">public</font> <font color="#0000ff">class</font> BangBean2 <font color="#0000ff">extends</font> Canvas
<font color="#0000ff">implements</font> Serializable {
<font color="#0000ff">private</font> <font color="#0000ff">int</font> xm, ym;
<font color="#0000ff">private</font> <font color="#0000ff">int</font> cSize = 20; <font color="#009900">// Circle size</font>
<font color="#0000ff">private</font> String text = "Bang!";
<font color="#0000ff">private</font> <font color="#0000ff">int</font> fontSize = 48;
<font color="#0000ff">private</font> Color tColor = Color.red;
<font color="#0000ff">private</font> Vector actionListeners = <font color="#0000ff">new</font> Vector();
<font color="#0000ff">public</font> BangBean2() {
addMouseListener(<font color="#0000ff">new</font> ML());
addMouseMotionListener(<font color="#0000ff">new</font> MM());
}
<font color="#0000ff">public</font> <font color="#0000ff">synchronized</font> <font color="#0000ff">int</font> getCircleSize() {
<font color="#0000ff">return</font> cSize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -