java.lang.Thread
Thread
or
implementing Runnable
Thread
public class GreetingThread extends Thread { public void run() { //thread action . . . } //variables used by the thread action . . . }
public run() { try { //thread action ) catch (InterruptedException exception) { //cleanup, if necessary } }
GreetingThread t = new GreetingThread("Hello World");
t.start();
Thu Dec 28 23:12:03 PST 2004 Hello, World! Thu Dec 28 23:12:03 PST 2004 Goodbye, World! Thu Dec 28 23:12:04 PST 2004 Hello, World! Thu Dec 28 23:12:05 PST 2004 Hello, World! Thu Dec 28 23:12:04 PST 2004 Goodbye, World! Thu Dec 28 23:12:05 PST 2004 Goodbye, World! Thu Dec 28 23:12:06 PST 2004 Hello, World! Thu Dec 28 23:12:06 PST 2004 Goodbye, World! Thu Dec 28 23:12:07 PST 2004 Hello, World! Thu Dec 28 23:12:07 PST 2004 Goodbye, World! Thu Dec 28 23:12:08 PST 2004 Hello, World! Thu Dec 28 23:12:08 PST 2004 Goodbye, World! Thu Dec 28 23:12:09 PST 2004 Hello, World! Thu Dec 28 23:12:09 PST 2004 Goodbye, World! Thu Dec 28 23:12:10 PST 2004 Hello, World! Thu Dec 28 23:12:10 PST 2004 Goodbye, World! Thu Dec 28 23:12:11 PST 2004 Goodbye, World! Thu Dec 28 23:12:11 PST 2004 Hello, World! Thu Dec 28 23:12:12 PST 2004 Goodbye, World! Thu Dec 28 23:12:12 PST 2004 Hello, World!
Runnable
Often more flexible to implement Runnable
than extend
Thread
Runnable
Runnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
1 public class Animal { 2 } 1 public class Cat extends Animal implements Runnable { 2 3 private final String msg; 4 private final long sleepTime; 5 6 public Cat(String msg, long sleepTime) { 7 this.msg = msg; 8 this.sleepTime = sleepTime; 9 } 10 11 public void run() { 12 13 while (true) { 14 15 System.out.println(msg); 16 try { 17 Thread.sleep(sleepTime); 18 } 19 catch (InterruptedException e) { 20 } 21 } 22 } 23 } 1 public class CatTest { 2 3 // Args to this application specify "msg" 4 // and "sleepTime" for multiple threads. 5 // For example, the command: 6 // 7 // $ java CatTest Meow 100 Grrr 1000 8 // 9 // requests two threads, one that prints 10 // out "Meow" every 100 milliseconds and 11 // another that prints out "Grrr" every 12 // 1000 milliseconds. 13 // 14 public static void main(String[] args) { 15 16 // Require an even argCount 17 int argCount = args.length; 18 if ((argCount / 2) == 1) { 19 --argCount; 20 } 21 22 for (int i = 0; i < argCount; i += 2) { 23 24 String msg = args[i]; 25 long sleepTime = Long.parseLong(args[i + 1]); 26 27 Cat cat = new Cat(msg, sleepTime); 28 29 Thread catThread = new Thread(cat); 30 catThread.start(); 31 } 32 } 33 }
setPriority()
.
yield()
indicates to the JVM that you are ready for
a rest. t1.run(); t2.run();instead of starting threads?
t.interrupt();
public void run() { try { for (int = 1; i <= REPETITIONS && !isInterrupted(); i++) { //do the work } } catch (InterruptedException exception) { // exit interrupted thread } //cleanup }
Applying Thread.sleep() or inJava 5 the utility TimeUnit class
volatile
Roughly speaking, a volatile field is safe for concurrent use by two or more
threads. More accurately, volatile says that the value of a field must always be
read from to main memory and that it may not be cached by a thread (in register
or CPU cache).
public class MyRunnable implements Runnable { public void run() { try { System.out.println(1); Thread.sleep(1000); System.out.println(2); } catch (InterruptedException exception) { System.out.println(3); } System.out.println(4); } }Suppose a thread with this runnable is started and immediately interrupted.
Thread t = new Thread(new MyRunnable()); t.start(); t.interrupt();What output is produced?
public void run() { try { for (int i = 1; i <= count; i++) { account.deposit(amount); Thread.sleep(DELAY); } } catch (InterruptedException exception) { } }
System.out.print("Depositing " + amount); double newBalance = balance + amount;
System.out.println(", new balance is " + newBalance); balance = newBalance;
public void deposit(double amount)
{
balance = balance + amount
;
System.out.print("Depositing " + amount + ", new balance is " + balance);
}
Race condition can still occur:
balance = the right-hand-side value
Depositing 100.0, new balance is 100.0 Withdrawing 100.0, new balance is 0.0 Depositing 100.0, new balance is 100.0 Withdrawing 100.0, new balance is 0.0 . . . Withdrawing 100.0, new balance is 400.0 Depositing 100.0, new balance is 500.0 Withdrawing 100.0, new balance is 400.0 Withdrawing 100.0, new balance is 300.0
public class BankAccount { public BankAccount() { balanceChangeLock = new ReentrantLock(); . . . } . . . private Lock balanceChangeLock; }
balanceChangeLock.lock(); Code that manipulates the shared resource balanceChangeLock.unlock();
public void deposit(double amount) { balanceChangeLock.lock(); try { System.out.print("Depositing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; } finally { balanceChangeLock.unlock(); } }
public void withdraw(double amount) { balanceChangeLock.lock(); try { while (balance < amount) Wait for the balance to grow . . . } finally { balanceChangeLock.unlock(); } }
public class BankAccount { public BankAccount() { balanceChangeLock = new ReentrantLock(); sufficientFundsCondition = balanceChangeLock.newCondition(); . . . } . . . private Lock balanceChangeLock; private Condition sufficientFundsCondition; }
public void withdraw(double amount) { balanceChangeLock.lock(); try { while (balance < amount) sufficientFundsCondition.await(); . . . } finally { balanceChangeLock.unlock(); } }
sufficientFundsCondition.signalAll();
Depositing 100.0, new balance is 100.0 Withdrawing 100.0, new balance is 0.0 Depositing 100.0, new balance is 100.0 Depositing 100.0, new balance is 200.0 . . . Withdrawing 100.0, new balance is 100.0 Depositing 100.0, new balance is 200.0 Withdrawing 100.0, new balance is 100.0 Withdrawing 100.0, new balance is 0.0
public class BankAccount { public synchronized void deposit(double amount) { . . . } public synchronized void withdraw(double amount) { . . . } . . . }
A monitor is a body of code (not necessarily contiguous, developed by C. A. R. Hoare), access to which is guarded by a mutual-exclusion locks (or mutex) that is associated with an object. The central notion of mutex is ownership. Only one thread can own the mutex at a time. If a second thread tries to acquire ownership, it will block (be suspended) until the owning thread releases the mutex.
synchronized(obj) { // guard code }
is effectively the same as this code:
obj.myMutex.acquire(); try { // guard code } finally { obj.myMutex.release(); }
public synchronized void withdraw(double amount) { while (balance < amount) //wait for balance to grow . . . }
public synchronized void withdraw(double amount) throws InterruptedException { while (balance < amount) wait(); }
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED
A thread can be in only one state at a given point in time. These states are virtual machine states which do not reflect any operating system thread states.
A thread in the blocked state is waiting for a monitor lock to
enter a synchronized block/method or reenter a synchronized block/method
after calling
Object.wait
A thread is in the waiting state due to calling one of the following methods:
Object.wait
with no timeout Thread.join
with no timeout A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:
Thread.sleep
Object.wait
with timeout Thread.join
with timeout class IsSafe { double x; public void synchronized mark() ( x = 0; } public void john() { x = -1; } }
Conceptually, a semaphore maintains a set of permits. Each
acquire()
blocks if necessary until a permit is available, and
then takes it. Each
release()
adds a permit, potentially releasing a blocking
acquirer. However, no actual permit objects are used; the Semaphore
just keeps a count of the number available and acts accordingly.
acquire()
obtain a permitacquire()
blocksSemaphore sem = new Semaphore (1, false);
The semaphore encapsulates the synchronization needed to restrict access to the pool, separately from any synchronization needed to maintain the consistency of the pool itself.
class Pool { private static final MAX_AVAILABLE = 100; private final Semaphore available = new Semaphore(MAX_AVAILABLE, true); public Object getItem() throws InterruptedException { available.acquire(); return getNextAvailableItem(); } public void putItem(Object x) { if (markAsUnused(x)) available.release(); } // Not a particularly efficient data structure; just for demo protected Object[] items = ... whatever kinds of items being managed protected boolean[] used = new boolean[MAX_AVAILABLE]; protected synchronized Object getNextAvailableItem() { for (int i = 0; i < MAX_AVAILABLE; ++i) { if (!used[i]) { used[i] = true; return items[i]; } } return null; // not reached } protected synchronized boolean markAsUnused(Object item) { for (int i = 0; i < MAX_AVAILABLE; ++i) { if (item == items[i]) { if (used[i]) { used[i] = false; return true; } else return false; } } return false; } }
- java.util.concurency.CountDownLatch
A synchronization aid that allows one or more threads to wait until a
set of operations being performed (preprocessing) in other threads completes.
A CountDownLatch is initialized with a given count. The
await
methods block until the current
count
reaches zero due to invocations of the
countDown()
method, after which all waiting threads are
released and any subsequent invocations of
await
return immediately.- java.util.concurency.Exchanger
A synchronization point provides for thread rendezvous at which two threads can exchange objects.
Each thread presents some object on entry to the
exchange
method, and receives the object presented by the
other thread on return.- java.util.concurency.CyclicBarrier
A synchronization aid (multiple thread rendezvous) that allows a set of threads to all wait for each
other to reach a common barrier point. CyclicBarrier
s are useful in programs
involving a fixed sized party of threads that must occasionally wait for
each other. The barrier is called cyclic because it can be re-used
after the waiting threads are released.
CyclicBarrier(int parties,
Runnable barrierAction)
public class SelectionSorter { public SelectionSorter(int[] anArray, Applet anApplet) { a = anArray; applet = anApplet; } . . . private Applet applet }
public void pause(int steps) throws InterruptedException { if (Thread.currentThread().isInterrupted()) throw new InterruptedException(); applet.repaint(); Thread.sleep(steps * DELAY); }
public void draw(Graphics2D g2) { int deltaX = applet.getWidth() / a.length; for (int i = 0; i < a.length; i++) { if (i == markedPosition) g2.setColor(Color.red); else if (i <= alreadySorted) g2.setColor(Color.blue); else g2.setColor(Color.black); g2.draw(new Line2D.Double(i * deltaX, 0, i * deltaX, a[i])); } }
public int minimumPosition(int from) throws InterruptedException { int minPos = from; for (int i = from + 1; i < a.length; i++) { if (a[i] < a[minPos]) minPos = i; markedPosition = i; pause(2); } return minPos; }
public class SelectionSortApplet extends Applet { public SelectionSortApplet() { class MousePressListener extends MouseAdapter { public void mousePressed(MouseEvent event) { if (animation != null && animation.isAlive()) animation.interrupt(); startAnimation(); } } MouseListener listener = new MousePressListener(); addMouseListener(listener); . . . animation = null; } . . . private Thread Animation }
public void paint(Graphics g) { if (sorter == null) return; Graphics2D g2 = (Graphics2D)g; sorter.draw(g2); }
public void startAnimation() { class AnimationThread extends Thread { public void run() { try { sorter.sort(); } catch (InterruptedException exception) { } } } int[] values = ArrayUtil.randomIntArray(30, 300); sorter = new SelectionSorter(values, this); animation = new AnimationThread(); animation.start(); }
exec()
method of the java.lang.Runtime
class. ProcessBuilder
. ProcessBuilder
in the java.lang
package (like
Runtime
and Process
). Runtime
class, also allows you to discover memory usage
and add a shutdown hook. exec()
method of Runtime
:
public Process exec(String command) throws IOException public Process exec(String command, String[] envp) throws IOException public Process exec(String command, String[] envp, File dir) throws IOException public Process exec(String[] cmdarray) throws IOExceptionjava public Process exec(String[] cmdarray, String[] envp) throws IOException public Process exec(String[] cmdarray, String[] envp, File dir) throws IOException
Runtime
: DoRuntime
Runtime
class.
import java.io.*; import java.util.*; public class DoRuntime { public static void main(String args[]) throws IOException { if (args.length <= 0) { System.err.println("Need command to run"); System.exit(-1); } Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec(args); InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line; System.out.printf("Output of running %s is:", Arrays.toString(args)); while ((line = br.readLine()) != null) { System.out.println(line); }// check for a command failure try { if (process.waitFor() != 0) System.err.println("exit value = " + process.exitValue()); } } catch (InterruptedException e) { System.err.println(e); } } }
DoRuntime
in Solaris like this: java DoRuntime ls
Output of running ls is:DoRuntime.class DoRuntime.java
cmd /c dir
" (again,
output would depend on the contents of the directory). >java DoRuntime "cmd /c dir" Volume in drive D is Users Volume Serial Number is 2841-2ED0Directory of D:\... 04/15/2006 09:30 AM <DIR> . 04/15/2006 09:30 AM <DIR> .. 04/15/2006 09:30 AM 1,146 DoRuntime.class 04/15/2006 09:23 AM 724 DoRuntime.java ...
exec()
command, you change: Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec(command);to:File file = new File(other directory); Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec(command, null, file);
exec()
method
identifies the environment variable settings. Because the parameter is
"null", the subprocess inherits the environment settings of the current
process. ProcessBuilder
: DoProcessBuilder
Runtime.exec
approach
doesn't necessarily make it easy to customize and invoke subprocesses.
ProcessBuilder
class simplifies things. Through various
methods in the class, you can easily modify the environment variables for
a process and start the process. import java.io.*; import java.util.*; public class DoProcessBuilder { public static void main(String args[]) throws IOException { if (args.length <= 0) { System.err.println("Need command to run"); System.exit(-1); } Process process = new ProcessBuilder(args).start(); InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line; System.out.printf("Output of running %s is:", Arrays.toString(args)); while ((line = br.readLine()) != null) { System.out.println(line); } // check for a command failure try { if (process.waitFor() != 0) System.err.println("exit value = " + process.exitValue()); } } catch (InterruptedException e) { System.err.println(e); } } } > java DoProcessBuilder ls Output of running ls is:DoProcessBuilder.class DoProcessBuilder.java DoRuntime.class DoRuntime.java
DoRuntime
: Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec(command);were changed to the following line inDoProcessBuilder
:Process process = new ProcessBuilder(command).start();
ProcessBuilder
ProcessBuilder
class has two constructors. List
for the command and its arguments.
String
arguments. public ProcessBuilder(List<String> command) public ProcessBuilder(String... command)
ProcessBuilder
, you call start()
to
execute the command. start()
, you can
manipulate how the Process
will be created. File
in as a command line argument. Instead, you set the
process builder's working directory by passing the File
to
the directory()
method: publicProcessBuilder
directory(File directory)
Map
of the variables through the
environment()
method, then you manipulate the
Map
: ProcessBuilder processBuilder = new ProcessBuilder(command); Map<String, String> env = processBuilder.environment(); // manipulate env
put()
method, and removing
them with the remove()
method. For example: ProcessBuilder processBuilder = new ProcessBuilder( command, arg1, arg2); Map<String, String> env = processBuilder.environment(); env.put("var1", "value"); env.remove("var3");
start()
: processBuilder.directory("Dir"); Process p = processBuilder.start();
clear()
all the variables from the
environment and explicitly set the ones you want. environment()
for adding and removing environment
variables from the process space, and start()
for starting a
new process, ProcessBuilder
should make it easier to invoke a
subprocess with a modified process environment. getenv()
method of System
. Understand that not all platforms support
changing environment variables. If you try to change an environment
variable on a platform that forbids it, the operation will throw either an
UnsupportedOperationException
or an
IllegalArgumentException
. Also, when running with a security
manager, you'll need the RuntimePermission
for
"getenv.*
", otherwise a SecurityException
will
be thrown.