Multi-Threading In Java

Why use threading?

  • Running long calculations in a separate worker thread allows programmers to provide a “Stop Calculation” button to users.
  • Threads enable programs to listen for user interruptions.
  • Threads enable parallelism within a program process. Each thread may take a different path of code execution through a program.
  • Multi-threading can be more efficient because it utilizes tiny slices of idle time present during program execution.
  • Single processor machines simulate simultaneous execution by running each thread for a very short time, then performing a context switch to another thread.
  • Threads make use of multiple processor machines (with two or more CPUs on a board). Each thread has it own resource overhead of local variables and program counters.

From: http://www.wilsonmar.com/1threads.htm

Synchronization and Threading

If you don’t when you should: If you do when you shouldn’t:
Data corruption, race conditions, potentially causing program to crash, incorrect results, or unpredictable behavior. These issues may be tricky to detect and reproduce (happen rarely and sporadically). Overuse or misuse of synchronization can lead to poor performance or deadlock.

“A race condition is a situation in which two or more threads or processes are reading or writing some shared data, and the final result depends on the timing of how the threads are scheduled. Race conditions can lead to unpredictable results and subtle program bugs.”

“To make your programs thread-safe, you must first identify what data will be shared across threads. If you are writing data that may be read later by another thread, or reading data that may have been written by another thread, then that data is shared, and you must synchronize when accessing it. … these rules also apply in situations where you are simply checking if a shared reference is non-null.”

“In simple cases, you can protect data fields by simply declaring them volatile; in other cases, you must acquire a lock before reading or writing the shared data, and it is a good practice to explicitly identify what lock is being used to protect a given field or object, and document that with your code.”

“The Collections classes … are un-synchronized, but for each interface defined in the framework, there is a synchronized wrapper (for example, Collections.synchronizedMap()) that wraps each method with a synchronized version.”

from: http://www.cs.wcupa.edu/~rkline/OS/Java_locks_semaphores.html (link no longer valid)

Thread Risks to Beware of:

  • Thread Starvation – Priorities are set in such a way that one thread never gets to run
  • Deadlock – When two threads are stuck because they are each waiting for a resource the other has (and is not giving up)
  • Lock inversion – When one thread attempts to aquire a lock but holds on it while attempting to acquire another lock
  • Blocking – A long running operation inside a lock may keep other threads from running
  • Critical Section Race Condition – Unpredictable results because multiple threads are using shared data without proper synchronization

Java’s Threading Model

Image from: http://www.wilsonmar.com/1threads.htm

Java Thread Concepts

Ways to Start Threads

  • extend the java.lang.Thread class
  • implement java.lang.Runnable

Yield

Threads should yield periodically to make sure other threads of the same priority have a chance to run:

Thread.yield();

Sleep

Thread.sleep(milliseconds);

  • yield() and sleep() are static methods within java.lang.Thread.
  • start() and run() are instance methods.

Priority

“Thread settings give hints to the thread scheduler, but do not guarantee a specific behavior… A Java thread’s priority is specified with an integer from (the lowest) 1 to 10 (the highest), constants Thread.MIN_PRIORITY and Thread.MAX_PRIORITY. By default, the setPriority method sets a thread’s priority to a value of 5 — the Thread.NORM_PRIORITY” –http://www.wilsonmar.com/1threads.htm

Volatile

Keyword to use on member variables to force individual threads to re-read the variable’s value from shared memory on every access and write back as soon as changes occur (prevents caching)

Interrupting a Thread

“Interrupting a thread means stopping what it is doing before it has completed its task, effectively aborting its current operation. Whether the thread dies, waits for new tasks, or goes on to the next step depends on the application.

“the method Thread.interrupt() does not interrupt a running thread. What the method actually does is to throw an interrupt if the thread is blocked, so that it exits the blocked state. More precisely, if the thread is blocked at one of the methods Object.wait, Thread.join, or Thread.sleep, it receives an InterruptedException, thus terminating the blocking method prematurely.

The best, recommended way to interrupt a thread is to use a shared variable to signal that it must stop what it is doing. The thread must check the variable periodically, especially during lengthy operations, and terminate its task in an orderly mannerJust be sure to declare the shared variable as volatile or enclose any access to it into synchronized blocks/methods.

But what happens if the thread is blocked waiting for some event?” It won’t hit your exit-test. Solution: Interrupt the thread with Thread.interrupt(). If the thread is blocked at one of the methods Object.waitThread.join, or Thread.sleep, it receives an InterruptedException, thus terminating the blocking method prematurely (does nothing if thread is not blocked). Then you can test the shared variable and stop.

But what happens if the thread is blocked on an I/O operation? I/O can block a thread for a considerable amount of time, particularly if network communication is involved. in Java 1.4, the blocked thread will get a ClosedByInterruptException exception….Or call the close() method of the socket the thread is blocked in. In this case, if the thread is blocked in an I/O operation, the thread will get a SocketException exception, much like the interrupt() method causes an InterruptedException to be thrown. The only caveat is that a reference to the socket must be available so that its close() method can be called. That means the socket object must also be shared.”

Thread.stop method: Although it indeed stops a running thread, the method is unsafe and was deprecated

From: http://builder.com.com/5100-6370_14-5144546.html (link no longer valid)