Beruflich Dokumente
Kultur Dokumente
Allen I. Holub
Holub Associates
www.holub.com
allen@holub.com
Middle
Beginning
Middle
Beginning
Middle
Beginning
Middle
Well look at
Books, etc.
Platform-dependence issues
Beginning
Middle
Beginning
Middle
03/06/2003
Words to live by
Middle
Middle
10
Priorities
Threading models
Preemptive (NT)
Middle
11
Middle
12
03/06/2003
NT threading model
13
Middle
14
Thread creation
Middle
15
Middle
16
17
Middle
18
03/06/2003
long x ;
64-bit assignment is
thread 1:
effectively implemented
x = 0x0123456789abcdef as:
thread 2:
x = 0;
possible results:
0x0123456789abcdef;
0x0123456700000000;
0x0000000089abcdef;
0x0000000000000000;
Middle
19
x.high = 0x01234567
x.low = 0x89abcdef;
Middle
20
Middle
21
22
Every object has its own monitor (and its own mutex).
Middle
long field;
Object lock = new Object();
synchronized(lock)
{ field = new_value
}
Middle
24
03/06/2003
Method-level synchronization
class Queue
{ public synchronized void enqueue(Object o)
{ /**/ }
public synchronized Object dequeue()
{ /**/ }
}
class Bathroom_window
{ private double guard_this;
25
26
class Predictable
{ Object lock = new Object();
public Predictable(int init_x, int init_y)
{ synchronized( lock )
{ new Thread()
{ public void run()
{ synchronized( lock )
{ // Use shared var
}
}
}.start();
//initialize shared var.
}
}
}
Middle
28
class Outer
{ private double
d;
private JButton b = new JButton();
public Outer()
{ b.addActionListener
( new ActionListener()
{ synchronized // grabs the wrong lock!
public void actionPerformed(ActionEvent e)
{ d = 0.0;
}
}
);
}
public void race_condition(double new_value)
{ d = new_value;
}
}
class Outer
{ private double
d;
private JButton b = new JButton();
public Outer()
{ b.addActionListener
( new ActionListener()
{ public void actionPerformed(ActionEvent e)
{ d = 0.0; // race condition!
}
}
);
}
public void race_condition(double new_value)
{ d = new_value;
}
}
29
Middle
class Unpredictable
{ private final int x;
private final int y;
Middle
// WRONG! Needs
// synchronization
Middle
30
03/06/2003
class Outer
{ private double
d;
private JButton b = new JButton();
public Outer()
{ b.addActionListener
( new ActionListener()
{ public void actionPerformed(ActionEvent e)
{ synchronized( Outer.this )
{ d = 0.0;
}
}
}
);
}
synchronized
public void race_condition(double new_value)
{ d = new_value;
}
}
Middle
31
class Synch
{
synchronized int locking
( int a, int
{ return a +
not_locking ( int a, int
{ return a +
static public void main(String[] arguments)
{ double start = new Date().get Time();
int
32
Synch
234 ms.
121.39% increase
139 ms.
149.29% increase
156 ms.
155.52% increase
157 ms.
155.87% increase
157 ms.
155.87% increase
155 ms.
154.96% increase
156 ms.
155.52% increase
3,891 ms. 1,484.70% increase
4,407 ms. 1,668.33% increase
BUT
The cost of stupidity is always higher than the cost
of synchronization. (Bill Pugh)
Pick a fast algorithm.
Overhead can be insignificant when the
synchronized method is doing a time-consuming
operation.
But in OO systems, small synchronized methods
often chain to small synchronized methods.
Middle
34
Reentrant Code
Volatile
Middle
Middle
b )
b;}
b )
b;}
Middle
36
03/06/2003
Middle
37
Middle
38
39
40
is really
Stringbuffer t0 = new StringBuffer(s2);
t0.append( s3 );
s1 = t0.toString();
Middle
41
42
// AAGH!
03/06/2003
compiler bug)
Middle
43
Middle
44
class Flintstone
{ public void fred()
{ synchronized( Flintstone.class )
{ // only one thread at a time
// can execute this code
}
}
public static synchronized void wilma()
{ // synchronizes on the same object
// as fred().
}
45
}
Middle
46
class Foo
{ static long x = 0;
synchronized static void set_x( long x )
{ Foo.x = x;
}
synchronized /* not static */ double get_x()
{ return x;
}
}
47
Middle
Critical sections
Middle
Thread 1:
Foo o1 = new Foo();
long x = o1.get_x();
Thread 2:
Foo.set_x(-1);
48
03/06/2003
class Okay
{ private static long unsafe;
public void foo(long x)
{ //...
synchronized( Okay.class )
{ unsafe = x;
}
}
}
class Okay
{ private
private
{return
private
{unsafe
Middle
49
Middle
50
class Okay
{ private static class Class_Variables
{ private long unsafe;
public synchronized void do_something(long x)
{ unsafe = x; //. . .
}
}
static Class_Variables statics =
new Class_Variables();
public foo(long x)
{ statics.do_something( x );
}
}
Middle
51
52
Or alternatively
Thread safe because VM loads only one class at a
time and method cant be called until class is fully
loaded and initialized.
public
/*unsynchronized*/ static Singleton instance()
{ return instance;
}
}
Middle
53
Middle
54
03/06/2003
Condition variables
55
56
Notifying_queue():
wait(), notify(), and spin locks
Middle
57
Middle
class Notifying_queue
{ private static final queue_size = 10;
private Object[]
queue = new Object[queue_size];
private int
head = 0;
private int
tail = 0;
public void synchronized enqueue( Object item )
{ queue[++head %= queue_size] = item;
this.notify();
}
public Object synchronized dequeue( )
{ try
{
while( head == tail) //<-- MUST BE A WHILE
this.wait();
//
(NOT AN IF)
}
catch( InterruptedException e )
{
return null; // wait abandoned
}
return queue[++tail %= queue_size ];
}
}58 Taming Java Threads, (c) 2002 Allen I Holub <www.holub.com>
Middle
59
Middle
60
10
03/06/2003
Middle
61
Middle
62
Middle
63
Middle
64
Visibility
Middle
65
CPU1
w rwwr w
CPU2
ww r r w r
MU1
memory
Middle
66
MU2
11
03/06/2003
Presto Chango!
The memory unit notices the inefficiency and rearranges
the requests!
CPU1
Consider:
memory
int a[] = new int[10];
int b[] = new int[10];
for( int i = 0; i < a.length; ++i )
b[i] = a[i];
To produce:
CPU1
CPU1
MU1
Wb[0..n]
Ra[0..n]
MU1
memory
MU1
memory
67
Middle
68
Dont Panic
BUT
69
Middle
MU1
CPU2
w w t&s t&s
MU2
70
MU2
class I_wont_work
{ private volatile boolean okay =
private long
field =
//. . .
public /*not synchronized*/ void
{
if( okay )
{ do something( field );
}
}
public /*not synchronized*/ void
{ okay = false;
field = 0;
okay = true;
}
}
memory
71
CPU2
ww r r w r
MU1
w rww rw
w r ww r w
Avoiding synchronization
(revisited)
CPU1
CPU1
memory
Middle
Middle
72
false;
-1;
wont_work()
Might be 1.
enable()
12
03/06/2003
Even worse
This works
Object lock = new Object();
Modification of s might
become visible before
modification of field if
memory unit rearranges
operations.
Thread 1:
synchronized( lock )
{ Surprised s = new Surprised();
}
Thread 2:
synchronized( lock )
{ System.out.println(s.get_field());
}
Thread 2:
System.out.println(s.field);
Middle
73
Middle
74
Middle
75
Middle
76
class Broken_singleton
{
public static Singleton instance()
{ if( instance == null )
{ synchronized( Singleton.class )
{
if( instance == null )
{
Singleton tmp = new Singleton();
instance = tmp;
}
}
}
return instance;
}
}
Middle
77
Middle
78
13
03/06/2003
79
Middle
80
www.primenet.com/~jakubik/mpsafe/
MultiprocessorSafe.pdf
Allen Holub:
www.javaworld.com/javaworld/ j w-02- 2001/
jw-0209-toolbox.html
Brian Goetz:
www.javaworld.com/javaworld/jw-02- 2001/
jw-0209-double.html
Middle
81
Middle
82
Middle
83
Middle
84
14
03/06/2003
Nested-monitor lockout
85
Can happen any time you call a method that can block
from any synchronized method.
Consider the following (I've removed exception handling):
class Black_hole
{ private InputStream input =
new Socket("www.holub.com",80)
.getInputStream();
public synchronized int read()
{ return input.read();
}
public synchronized void close()
{ input.close();
}
}
Middle
86
class Black_hole2
{ Notifying_queue queue =
new Notifying_queue();
public synchronized void put(Object thing)
{ queue.enqueue(thing);
}
Middle
87
Middle
88
class Right
class Wrong
{ private Thread t =
{ private Thread t =
new Thread()
new Thread()
{ public void run()
{ public void run()
{ try
{ while( true )
{ while( !isInterrupted () )
{ //...
{ //...
blocking_call();
blocking_call();
}
}
}
}catch(InterruptedException e)
};
{/*ignore, stop request*/}
public stop()
}
{ t.stop();
};
}
public stop()
}
{t.interrupt() ;}
}
89
Middle
90
15
03/06/2003
interrupt() gotchas
class Wrong
{ public synchronized
void take_a_nap()
{
suspend();
}
public synchronized
void wake_up()
{
resume();
}
}
91
Middle
92
class Right
{
public synchronized
void take_a_nap()
{ try
{
wait();
}
catch(InterruptedException e)
{/*do something reasonable*/}
}
public synchronized
void wake_up()
{
notify();
}
}
Middle
93
Middle
94
Condition Variable
Thread Pools
A group of dormant threads wait for something to do.
A thread activates to perform an arbitrary task.
Timers
Counting Semaphore
95
96
16
03/06/2003
Reader/Writer Locks
Middle
97
Middle
98
class Receiver
{ //. . .
public asynch_method()
{ new Thread()
{
public void run()
{ synchronized( Receiver.this )
{ // Make local copies of
// outer-class fields here.
}
// Code here doesn't access outer
// class (or uses only constants).
}
}.start();
}
}
Middle
99
Middle
100
class Flush_example
{ public interface Error_handler
{
void error( IOException e );
}
private final OutputStream out;
private final Reader_writer lock =
new Reader_writer();
private byte[]
buffer;
private int
length;
public Flush_example( OutputStream out )
{ this.out = out;
}
Middle
101
Middle
}102
17
03/06/2003
Middle
103
= .0040 ms.
= .0491 ms.
= .8021 ms. (NT 4.0, 600MHz)
Middle
104
105
Middle
106
Middle
107
Middle
108
18
03/06/2003
109
Middle
Summing up
class Console
{
private static Active_object dispatcher
= new Active_object();
static{ dispatcher.start(); }
private Console(){}
}
Middle
111
Middle
End
112
113
19