Threading and Concurrency Issues Creating Threads In Java

  • Slides: 14
Download presentation
Threading and Concurrency Issues Creating Threads ● In Java ● Subclassing Thread ● Implementing

Threading and Concurrency Issues Creating Threads ● In Java ● Subclassing Thread ● Implementing Runnable ● Synchronization ● Immutable ● Synchronized Methods ● Synchronized Blocks ● Performance Issues ● Thread Pooling ● Transactions and Threading ● Thread safety issues ● Thread-safe ● Immutable ● Thread-hostile ●

Creating Threads ● In Java, there are two options: ● Subclass the Thread class

Creating Threads ● In Java, there are two options: ● Subclass the Thread class ● Implement Runnable Subclassing is usually the poorest choice because you force threaded class into an inheritance hierarchy. ● ● The most flexible solution is to implement Runnable.

Subclassing Thread public class Test extends Thread { // The start method is defined

Subclassing Thread public class Test extends Thread { // The start method is defined in the // Thread class. When called, it creates // a new thread and the new thread invokes // “run” on the current object public void run() { // This method runs in its // own thread } } Thread 1 start() Thread Object run() Thread 2

Implementing Runnable public class Test implements Runnable { private Thread the. Thread; public void

Implementing Runnable public class Test implements Runnable { private Thread the. Thread; public void start() { if (the. Thread == null) { the. Thread = new Thread(this); the. Thread. start(); } } public void run() { // This method runs in its // own thread } Thread(Runnable) start() Thread Object run() create start() Runnable Object Thread 2 run() Thread 1

Terminating Threads When Java was first introduced, the multi-threading library offered a method called

Terminating Threads When Java was first introduced, the multi-threading library offered a method called stop(). ● This method was invoked to stop a thread. ● However, it turned out that use of the stop method could lead to deadlock conditions ● When the stop method was invoked the thread would stop immediately and it wasn't given the opportunity to release any resources that it held. ● Uncontrolled stopping of a thread would give rise to unsafe conditions. ● The correct way to terminate a thread is for the thread to return from the “run” method ● This is usually accomplished through setting a boolean variable which is periodically checked within the run method. ●

Terminating Threads public class Test implements Runnable { private Thread the. Thread; private boolean

Terminating Threads public class Test implements Runnable { private Thread the. Thread; private boolean stop. Thread = false; public void start() { if (the. Thread == null) { the. Thread = new Thread(this); the. Thread. start(); } } public void set. Stop. Thread(boolean a. Value) { stop. Thread = a. Value; } public void run() { while(!stop. Thread) { //. . . } }

Synchronization As you learned in CPSC 457, multi-threaded applications are subject to concurrency problems

Synchronization As you learned in CPSC 457, multi-threaded applications are subject to concurrency problems ● When two threads attempt to update the same data at the same time, the execution of the threads can become interleaved which gives rise to race conditions ● Race conditions can cause erroneous results in computation ● ● To prevent corruption, the programmer must identify shared variables. ● Access to these variables must be mutually exclusive in time between threads ● ie. only one thread may update a shared variable at any given point in time Java provides a “synchronized” keyword which is used to guarantee mututal exclusion in time. ●

Object monitors In order to accomplish mutual exclusion, each object in java is provided

Object monitors In order to accomplish mutual exclusion, each object in java is provided with a monitor (or lock). ● The lock cannot be directly accessed, it can only be access through the use of the synchronized keyword. ● If a method or block is synchronized, then a thread may not enter the method or block until it has obtained the monitor. ● If a thread cannot obtain the lock for the given method or block, it becomes blocked by the scheduler until such time that the monitor becomes available ● ● The testing and setting of the monitor is guaranteed to be atomic.

Synchronized methods The easiest way of obtaining mutual exclusion in Java is by defining

Synchronized methods The easiest way of obtaining mutual exclusion in Java is by defining methods as synchronized. ● If a method is synchronized, the monitor of the target object is obtained. ● ● It is possible to define multiple synchronized methods within a class. ● This guarantees that only one thread may be executing any of the synchronized methods at a give point in time. public class Savings. Account { private float balance; public synchronized void withdraw(float an. Amount) { if ((an. Amount>0. 0) && (an. Amount<=balance)) balance = balance - an. Amount; } public synchronized void deposit(float an. Amount) { if (an. Amount>0. 0) balance = balance + an. Amount; }

Synchronization and performance ● Unfortunately, synchronization comes with a price. ● Performance suffers because

Synchronization and performance ● Unfortunately, synchronization comes with a price. ● Performance suffers because threads which could be executing are blocked if another thread is currently executing a synchronized method on the target object. The solution to this problem is to make the area which is synchronized as small as possible ● Methods do not offer fine enough granularity. ● It is possible to synchronize blocks instead of whole methods. ●

Synchronized blocks public class Savings. Account { private float balance; public void withdraw(float an.

Synchronized blocks public class Savings. Account { private float balance; public void withdraw(float an. Amount) { if (an. Amount<0. 0) throw new Illegal. Argument. Exception("Withdraw amount negative"); synchronized(this) { if (an. Amount<=balance) balance = balance - an. Amount; } } public void deposit(float an. Amount) { if (an. Amount<0. 0) throw new Illegal. Argument. Exception("Deposit amount negative"); synchronized(this) { balance = balance + an. Amount; } }

Synchronized blocks and methods: ● This method: public synchronized void withdraw(float an. Amount) {

Synchronized blocks and methods: ● This method: public synchronized void withdraw(float an. Amount) { if ((an. Amount>0. 0) && (an. Amount<=balance)) balance = balance - an. Amount; } is equivalent to this method: public void withdraw(float an. Amount) { synchronized(this) { if ((an. Amount>0. 0) && (an. Amount<=balance)) balance = balance – an. Amount; } }

Other performance considerations While the creation of threads is a relatively inexpensive operation (particularly

Other performance considerations While the creation of threads is a relatively inexpensive operation (particularly when compared to creating processes), there is still an overhead should an application be creating and terminating a large number of threads. ● ● One general solution is to create a thread pool: ● References to the Runnable objects are kept in a collection and pulled out when needed ● Runnable objects obtain their work (in the form of transactions) from a queue. If no work is available, the thread blocks.

General Threading Considerations Avoid over-synchronization ● Don't write code which depends on how the

General Threading Considerations Avoid over-synchronization ● Don't write code which depends on how the scheduler is going to behave ● Always invoke wait within a loop ● Never use thread groups ● Never use stop() or resume() ● Document Thread Safety ● Immutable: Data cannot change. No external synchronization is necessary ● Thread-safe: instance of the class are mutable, but the methods contain sufficient internal synchronization so that the methods can be used without any external synchronization ● Conditionally thread-safe: Some methods must be invoked in a specific order or external synchronization must be provided. ● Thread-compatible: Instances can be used concurrently provided that each method is protected by external synchronization ● Thread-hostile: cannot be used concurrently, even if external synchronization is provided. ●