Monday, May 18, 2015

Keynote: Threads like trains:)

Using the Threads leverage your application speed & flexibility:


A thread can be only in one of five states:
State Description
New When created but not started - not alive yet.
Runnable Eligible to run. either when start() method is invoked or returned or coming back from a blocked, waiting, or sleeping state - alive.
Running The scheduler chooses a thread from the runnable pool and it becomes the currently executing process.
Wait/blocking/sleeping The thread is still alive, but is currently not eligible to run. - considered alive.
Deads run() method completed - it's no longer a separate thread of execution and never be brought back to life! If you invoke start() on a dead Thread instance, you'll get a runtime exception. - not alive.

Start the Thread


To start the new thread thread start() instance method should be invoked, which pass thread into runnable (but not running!) state.

There are two ways: you can either pass Runnable object into thread constructor or extend the Thread class, which itself implements Runnable.
...
public static void main(String args[]) {
    // pass runnable impplementation
    (new Thread(new HelloRunnable())).start();

    // start Thread descendant with own run method 
    (new HelloThread()).start();

    // legal but have no any sense
    (new Thread(new HelloThread()).start());
}
...    
class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }
}
...    
class HelloThread extends Thread {
    public void run() {
        System.out.println("Hello from a thread!");
    }
}

If you create a thread using the no-arg constructor, the thread will call its own run() method when it's time to start working. That's exactly what you want when you extend Thread, but when you use Runnable, you need to tell the new thread to use your run() method rather than its own.
There is nothing in the Java spec that says threads will start running in the order in which they were started.
And there is no guarantee that once a thread starts executing, it will keep executing until it's done. Or that a loop will complete before another thread begins...
Once a thread has been started, it can never be started again.
If you call start() a second time, it will cause an exception (an IllegalThreadStateException, which is a kind of RuntimeException).A runnable thread or a dead thread cannot be restarted. Only a new thread can be started, and then only once.
Almost always is better to implement Runnable instead of direct extension of Thread.
It's more flexible, cause Runnable can be subclass of any other class than Thread.

Pause the Thread

Thread.sleep causes the currently-executing thread to suspend execution for a specified period.
Pausing thread is useful to make CPU time available for another threads or applications.
Also it used during the code instrumentation.

There two overloaded sleep methods, so u can either pass time argument in milliseconds or nanoseconds.
sleep throws InterruptedException when another thread interrupts the current thread while sleep is active.
So, u've to wrap Thread.sleep() invocation into try/catch block or specify.
Instead of simple Thread.sleep() u can use ScheduledExecutorService for more advanced control:
private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
...
executor.scheduleWithFixedDelay(runnable, DEFAULT_CHECK_INTERVAL_SEC, 
DEFAULT_UPDATE_CHECK_INTERVAL_SEC, TimeUnit.SECONDS);
or
    
private ScheduledExecutorService executor = Executors.newScheduledThreadPool(BROADCASTER_THREAD_POOL_SIZE);
...
for (int counter = 1; counter <= broadcastNumPerRound; counter++) {
  executor.schedule(new CustomRunnableBroadcaster(serviceBus, subscriptions),             BROADCASTER_TIME_PERIOD_SEC * counter, TimeUnit.SECONDS);
}

Interrupt the Thread

An interrupt is an indication to a thread that it should stop what it is doing and do something else.
The interrupted thread must support its own interruption.
So, if the thread is blocked by such methods like wait(), joint() or Thread.sleep() which could throw InterruptedException, the invocation those should be wrapped into try/catch block or specified.
Invoking threads interrupt() sets the internal interrupt status flag.
When a thread checks for an interrupt by invoking the static method Thread.interrupted, interrupt status cleared!
The non-static isInterrupted method, which is used by one thread to query the interrupt status of another, does not change the interrupt status flag.

Join to another Thread

Invocation of join method on some Thread instance cause the current thread pause until that thread terminates.
Other words it's like saying, "Hey, thread, I want to join on to the end of you. Let me know when you're done, so I can enter the runnable state."
Thread t = new Thread(new MessagesLoopRunnable());
t.start();
// wait indefinitely for MessageLoop thread to finish.
t.join();

Threads priority

If not explicitly set via setPriority() method, a thread's priority will have the same priority as the thread that created it.

For a typical single-processor machine, only one thread can be running at a time, although many threads may be in the runnable state.

The thread scheduler can move a thread back and forth between the runnable state and the running state.
When a thread is running, it will usually not have a lower priority than any thread in the runnable state. If a low-priority thread is running when a high-priority thread enters runnable, the JVM will usually preempt the running low-priority thread and put the high-priority thread in.
There is no guarantees about order in which the threads will run, so u should never rely on it in your applications!

It's up to the thread scheduler, as determined by the particular virtual machine implementation.
If you want a guarantee that your threads will take turns, regardless of the JVM, you can use the sleep() method.
In most cases, yield() method works well enough to encourage your threads to play together nicely.

The yield() method may cause a running thread to back out if there are runnable threads of the same priority. There is no guarantee that this will happen, and that the thread chosen back out from there will be a different thread selected to run.
A thread might yield and then immediately reenter the running state.

Thread`s Synchronization

Thread Interference - Occurs when two operations, running in different threads, but acting on the same data, interleave, so their steps sequences overlap.
It's also known as race condition - multiple threads can access the same resource (typically an object's instance variable) and can produce corrupted data if one thread races in too quickly before an operation that should be atomic has completed.

Another problem is Memory consistency errors - happen when different threads have inconsistent views of what should be the same data. The happens-before relationship is simply a guarantee, that memory writes by one specific statement are visible to another specific statement.
Happens-before relations:
When a statement invokes thread.start, every statement that has a happens-before relationship with that statement also has a happens-before relationship with every statement executed by the new thread.
The effects of the code that led up to the creation of the new thread are visible to the new thread.
When a thread terminates and causes a thread.join in another thread to return, then all the statements executed by the terminated thread have a happens-before relationship with all the statements following the successful join.
The effects of the code in the thread are now visible to the thread that performed the join.
Every object in Java has a built-in lock (intrinsic-lock), which we automatically acquire only when enter a synchronized method and release it when the method returns (even if the return was caused by an uncaught exception).
There is only one lock per object.
If one thread has picked up the lock, no other thread can pick up the lock (or enter any synchronized method of that object), until the first thread releases (or returns) the lock (exits the synchronized method).
1. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
2. When a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object.
This guarantees that changes to the state of the object are visible to all threads.
Only methods (or blocks) can be synchronized, not variables or classes.
Constructors cannot be synchronized! - syntax error.

* Threads calling non-static synchronized methods in the same class will only block each other if they're invoked using the same instance. That's because they each lock on this instance, and if they're called using two different instances, they get two locks, which do not interfere with each other.
static methods can be synchronized.
It's possible to synchronize those via specifying the class-literal e.g. MyClass.class, which is the instance of Class that represents the class called MyClass.

* Threads calling static synchronized methods in the same class will always block each other—they all lock on the same Class instance.
A static synchronized method and a non-static synchronized method will not block each other, ever.

* The static method locks on a Class instance, while the non-static method locks on the this instance— these actions do not interfere with each other at all.
You can synchronize a block of code rather than a method.

When you synchronize a method, the object used to invoke the method is the object whose lock must be acquired.
But when you synchronize a block of code, you specify which object's lock you want to use as the lock, so you could, for example, use some third-party object as the lock for this piece of code.
So, you could always replace a synchronized method with a non-synchronized method containing a synchronized block:
public synchronized void doStuff() {
    System.out.println("synchronized");
}
is equivalent to this:
public synchronized void doStuff() {
    synchronized(this) {
        System.out.println("synchronized");
    }
}

Synchronized statements are useful for improving concurrency with fine-grained synchronization. Instead of using synchronized methods or otherwise using the lock associated with this, we create two objects solely to provide locks:
public class ParallelInc {
    private long c1 = 0;
    private long c2 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();
    
    public void inc1() {
        synchronized(lock1) {
            c1++;
        }
    }
    
    public void inc2() {
        synchronized(lock2) {
            c2++;
        }
    }
}
It allows the independent parts of hte same class to act without interference & blocking each other.

Reentrant Synchronization

A thread can acquire more than one lock.

Thread cannot acquire a lock owned by another thread, but a thread can acquire a lock that it already owns.

So, allowing a thread to acquire the same lock enables reentrant synchronization, which happens where synchronized code, directly or indirectly, invokes a method that also contains synchronized code, and both sets of code use the same lock.
In other words, there no problem if a thread acquires a lock and then attempts to call a synchronized method on that same object.
The JVM knows that this thread already has the lock for this object, so the thread is free to call other synchronized methods on the same object, using the lock the thread already has.

No comments:

Post a Comment