Thread - Answers A thread is the flow of execution, from beginning to end, of a task. It provides the
mechanism for running a task; you can launch multiple threads from a program concurrently in Java.
In single-processor systems, the multiple threads share CPU time - called time sharing.
Every task in Java is an instance of the Runnable interface, called a runnable object. A thread is basically
an object that facilitates execution of a task.
Creating Tasks - Answers Tasks are objects, implementing the Runnable interface - which only contains
the run() method.
A task must be executed in a thread:
Thread thread = new Thread(task);
then tell the JVM it's ready to run like:
thread.start();
When the run() method completes, the thread terminates. Invoking run() directly doesn't create a new
thread, so don't do it.
Thread Class - Answers The Thread class implements Runnable interface - which means you could write
the run() method inside the Thread class, but it's not recommended because you're mixing the task and
the mechanism of running the task.
Thread's methods:
isAlive() returns if a thread is currently running
setPriority(int) can set priority from 1 to 10
join() waits for the thread it's called on to finish
,sleep(millis : long) puts a thread to sleep for specified number of milliseconds
yield() - temporarily releases time for other threads
interrupt() - interrupts the thread
To call sleep(), surround the call with a try, catch(InterruptedException ex) block, putting it around the
loop if sleep() is called inside a loop.
Threads inherit priority of the thread that created it. For setPriority(), the Thread class has the int
constants MIN_PRIORITY, NORM_PRIORITY (5, the priority of the main thread), and MAX_PRIORITY.
The JVM always picks the currently runnable thread with the highest priority, and lower-priority threads
can only run when no higher-priority threads are running. If all the priorities are equal, they all get an
equal portion of CPU time, called round-robin scheduling.
Contention / Starvation - Answers When a lower-priority thread never gets a chance to run because
there are always higher-priority threads, or a same-priority thread that never yields. To avoid this, the
thread with higher priority must periodically call the sleep() or yield() method to give threads with a
lower or the same priority a chance to run.
Thread Pools - Answers Starting a new thread for each task is inefficient, so we use a thread pool instead
to manage tasks executing concurrently.
There is the Executor interface for executing tasks in a thread pool, and the ExecutorService interface for
managing and controlling tasks, and it's a subinterface of Executor.
From the Executors class, use the newFixedThreadPool(int) to create a fixed number of threads in a
pool, and this will return an ExecutorService object. If a thread completes a task, it can be reused to
execute another task - if a thread terminates before shutdown, a new thread will be created to replace
it if all other threads are idle and there are still tasks to be done.
The newCachedThreadPool() creates a new thread if all the threads in the pool are not idle and there
are tasks to be executed; a thread in a cached pool will be terminated if it's inactive for 60 seconds.
, ExecutorService executor = Executors.newFixedThreadPool(3);
executor.excute(new Runnable(paramaters));
...
executor.shutdown(); // tells the executor to shut down - no new tasks can be accepted, but existing
tasks will continue to finish, unlike the shutdownNow() method, which returns a list of unfinished tasks.
Race condition, thread safe - Answers A race condition is when different tasks are accessing a common
resource in a way that causes a conflict; a class is said to be thread-safe if an object of this class doesn't
cause a race condition in the presence of multiple threads.
The Synchronized keyword - Answers To prevent race conditions, we have to stop more than one thread
from accessing a certain part of the program simultaneously, called the critical region / critical section.
You can use the keyword "synchronized" in the method declaration so only one thread can access it at a
time.
A synchronized method gets a lock before it executes, which allows it to exclude other threads. For an
instance method, the lock is on the object for which the method was invoked; for a static method, the
lock is on the class.
If one thread invokes a synchronized instance method on an object, the lock of that object is acquired
first, then the method is executed, and finally the lock is released; another thread invoking the same
method is blocked until the lock is released. The same is true if it's a static method, but with the lock on
the class instead.
Synchronized blocks - Answers You can synchronize more than just this object, but any object:
synchronized (expr) { ....}