The document discusses multithreaded programming in Java. It covers key topics like:
- Java allows developing multithreaded programs where parts can run concurrently using threads.
- Threads can run in parallel and the OS divides processing time among threads within an application.
- Threads have priorities that help determine scheduling order, with higher priority threads running first.
- Synchronization is needed to prevent thread conflicts when accessing shared resources.
- The Thread class and Runnable interface are used to create and manage threads in Java programs.
The document discusses multithreaded programming in Java. It covers key topics like:
- Java allows developing multithreaded programs where parts can run concurrently using threads.
- Threads can run in parallel and the OS divides processing time among threads within an application.
- Threads have priorities that help determine scheduling order, with higher priority threads running first.
- Synchronization is needed to prevent thread conflicts when accessing shared resources.
- The Thread class and Runnable interface are used to create and manage threads in Java programs.
The document discusses multithreaded programming in Java. It covers key topics like:
- Java allows developing multithreaded programs where parts can run concurrently using threads.
- Threads can run in parallel and the OS divides processing time among threads within an application.
- Threads have priorities that help determine scheduling order, with higher priority threads running first.
- Synchronization is needed to prevent thread conflicts when accessing shared resources.
- The Thread class and Runnable interface are used to create and manage threads in Java programs.
• Java is a multi-threaded programming language which means
we can develop multi-threaded program using Java. • A multi-threaded program contains two or more parts that can run concurrently and each part can handle a different task at the same time making optimal use of the available resources specially when your computer has multiple CPUs. • By definition, multitasking is when multiple processes share common processing resources such as a CPU. • Multi-threading extends the idea of multitasking into applications where you can subdivide specific operations within a single application into individual threads. • Each of the threads can run in parallel. • The OS divides processing time not only among different applications, but also among each thread within an application. • Multi-threading enables you to write in a way where multiple activities can proceed concurrently in the same program. Life Cycle of a Thread Thread Priorities • Every Java thread has a priority that helps the operating system determine the order in which threads are scheduled. • Java thread priorities are in the range between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a constant of 10). By default, every thread is given priority NORM_PRIORITY (a constant of 5). • Threads with higher priority are more important to a program and should be allocated processor time before lower-priority threads. • A thread’s priority is used to decide when to switch from one running thread to the next. • This is called a context switch. • The rules that determine when a context switch takes place are simple: • A thread can voluntarily relinquish control. This is done by explicitly yielding, sleeping, or blocking on pending I/O. In this scenario, all other threads are examined, and the highest-priority thread that is ready to run is given the CPU. • • A thread can be preempted by a higher-priority thread. In this case, a lower-priority thread that does not yield the processor is simply preempted—no matter what it is doing— by a higher-priority thread. Basically, as soon as a higher-priority thread wants to • run, it does. This is called preemptive multitasking. Synchronization • For example, if you want two threads to communicate and share a complicated data structure, such as a linked list, you need some • way to ensure that they don’t conflict with each other. That is, you must prevent one thread from writing data while another thread is in the middle of reading it. • For this purpose, Java implements an elegant twist on an age-old model of interprocess synchronization: the monitor • Once a thread enters a monitor, all other threads must wait until that thread exits the monitor. • In this way, a monitor can be used to protect a shared asset from being manipulated by more than one thread at a time. The Thread Class and the Runnable Interface • Java’s multithreading system is built upon the Thread class, its methods, and its companion interface, Runnable. • To create a new thread, your program will either extend Thread or implement the Runnable interface. The Thread class defines several methods that help manage threads The Main Thread • When a Java program starts up, one thread begins running immediately. • This is usually called the main thread of your program, because it is the one that is executed when your program begins. • The main thread is important for two reasons: – It is the thread from which other “child” threads will be spawned. – Often, it must be the last thread to finish execution because it performs various shutdown actions. • The main thread is created automatically when your program is started, it can be controlled through a Thread object. To do so, you must obtain a reference to it by calling the method currentThread( ). • class CurrentThreadDemo { • public static void main(String args[]) { • Thread t = Thread.currentThread(); • System.out.println("Current thread: " + t); • // change the name of the thread • t.setName("My Thread"); • System.out.println("After name change: " + t); • try { • for(int n = 5; n > 0; n--) { • System.out.println(n); • Thread.sleep(1000); • } • } catch (Interrupted Exception e) { • System.out.println("Main thread interrupted"); • }}} Output • Current thread: Thread[main,5,main] • After name change: Thread[MyThread,5,main] • 5 • 4 • 3 • 2 • 1 Creating a Thread • In the most general sense, you create a thread by instantiating an object of type Thread. • Java defines two ways in which this can be accomplished: – You can implement the Runnable interface. – You can extend the Thread class, itself. 1) Implementing Runnable • The easiest way to create a thread is to create a class that implements the Runnable interface. • To implement Runnable, a class need only implement a single method called run( ), which is declared like this: • public void run( ) • run( ) can call other methods, use other classes, and declare variables, just like the main thread can. • The only difference is that run( ) establishes the entry point for another, concurrent thread of execution within your program. • This thread will end when run( ) returns. • After you create a class that implements Runnable, you will instantiate an object of type Thread from within that class. • Thread defines several constructors. The one that we will use is shown here: • Thread(Runnable threadOb, String threadName) • In this constructor, threadOb is an instance of a class that implements the Runnable interface. • This defines where execution of the thread will begin. The name of the new thread is specified by threadName. • After the new thread is created, it will not start running until you call its start( ) method, which is declared within Thread. • In essence, start( ) executes a call to run( ). Simple example • class Mythread implements Runnable • { • public void run() • { • System.out.println(“Hello”); • } • } • class Thread{ • public static void main(String args[]) • { • Mythread x= new Mythread(); • Thread t=new Thread(x); • t.start(); • } • } Here is an example that creates a new thread and starts it running: • class NewThread implements Runnable { • Thread t; • NewThread() { • // Create a new, second thread • t = new Thread(this, "Demo Thread"); • System.out.println("Child thread: " + t); • t.start(); // Start the thread • } • // This is the entry point for the second thread. • public void run() { • try { • for(int i = 5; i > 0; i--) { • System.out.println("Child Thread: " + i); • Thread.sleep(500); • } • } catch (InterruptedException e) { • System.out.println("Child interrupted."); • } • System.out.println("Exiting child thread."); • }} • class ThreadDemo { • public static void main(String args[]) { • new NewThread(); // create a new thread • try { • for(int i = 5; i > 0; i--) { • System.out.println("Main Thread: " + i); • Thread.sleep(1000); • } • } catch (InterruptedException e) { • System.out.println("Main thread interrupted."); • } • System.out.println("Main thread exiting."); • } • } • Child thread: Thread[Demo Thread,5,main] • Main Thread: 5 • Child Thread: 5 • Child Thread: 4 • Main Thread: 4 • Child Thread: 3 • Child Thread: 2 • Main Thread: 3 • Child Thread: 1 • Exiting child thread. • Main Thread: 2 • Main Thread: 1 • Main thread exiting. Extending Thread • The second way to create a thread is to create a new class that extends Thread, and then to create an instance of that class. • The extending class must override the run( ) method, which is the entry point for the new thread. It must also call start( ) to begin execution of the new thread. • public class FirstThread extends Thread • { • public void run() • { • for (int i=1; i<=10; i++) • { • System.out.println( "Messag from First Thread : " +i); • • try • { • Thread.sleep(1000); • } • catch (InterruptedException interruptedException) • { • System.out.println( "First Thread is interrupted when it is sleeping" +interruptedException); • } • } • } • } • public class SecondThread extends Thread • { • • public void run() • { • • for (int i=1; i<=10; i++) • { • System.out.println( "Messag from Second Thread : " +i); • try • { • Thread.sleep (1000); • } • catch (InterruptedException interruptedException) • { • System.out.println( "Second Thread is interrupted when it is sleeping" +interruptedException); • } • } • } • } • public class ThreadDemo • { • • public static void main(String args[]) • { • • //Creating an object of the first thread • FirstThread firstThread = new FirstThread(); • • //Creating an object of the Second thread • SecondThread secondThread = new SecondThread(); • • //Starting the first thread • firstThread.start(); • • //Starting the second thread • secondThread.start(); • } • } • Output of ThreadDemo Using isAlive() and join() • Sometimes one thread needs to know when another thread is ending. • In java, isAlive() and join() are two different methods to check whether a thread has finished its execution. • The isAlive() method returns true if the thread upon which it is called is still running otherwise it returns false. • final boolean isAlive() • But, join() method is used more commonly than isAlive(). • This method waits until the thread on which it is called terminates. • final void join() throws InterruptedException • Using join() method, we tell our thread to wait until the specified thread completes its execution. • There are overloaded versions of join() method, which allows us to specify time for which you want to wait for the specified thread to terminate. • final void join(long milliseconds) throws InterruptedException Example isAlive() • public class MyThread extends Thread { • public void run() • { System.out.println("r1 "); • try { Thread.sleep(500); } catch(InterruptedException ie) { } System.out.println("r2 "); } • public static void main(String[] args) • { MyThread t1=new MyThread(); • MyThread t2=new MyThread(); • t1.start(); • t2.start(); • System.out.println(t1.isAlive()); System.out.println(t2.isAlive()); • }} Example join() • class TestJoinMethod1 e • TestJoinMethod1 t3=ne xtends Thread{ w TestJoinMethod1(); • public void run(){ • t1.start(); • for(int i=1;i<=5;i++){ • try{ • try{ • t1.join(); • Thread.sleep(500); • }catch(Exception e) • }catch(Exception e) {System.out.println(e);} {System.out.println(e);} • • System.out.println(i); • t2.start(); • } • t3.start(); • } • } • public static void main(St • } ring args[]){ • TestJoinMethod1 t1=ne w TestJoinMethod1(); • TestJoinMethod1 t2=ne Output • 1 • 2 • 3 • 4 • 5 • 1 • 1 • 2 • 2 • 3 • 3 • 4 • 4 • 5 • 5 Threads priority • To set a thread’s priority, use the setPriority( ) method, which is a member of Thread. • This is its general form: • final void setPriority(int level) • Here, level specifies the new priority setting for the calling thread. The value of level must be within the range MIN_PRIORITY and MAX_PRIORITY. Currently, these values are 1 and 10, respectively. • To return a thread to default priority, specify NORM_PRIORITY, which is currently 5. These priorities are defined as static final variables within Thread. • You can obtain the current priority setting by calling the getPriority( ) method of Thread, shown here: • final int getPriority( ) • class TestMultiPriority1 extends Thread • { public void run( • ) { System.out.println("running thread name is:"+Thre ad.currentThread().getName()); • System.out.println("running thread priority is:"+Thr ead.currentThread().getPriority()); • } • public static void main(String args[]) • { TestMultiPriority1 m1=new TestMultiPriority1); T estMultiPriority1 m2=new TestMultiPriority1(); m1.s etPriority(Thread.MIN_PRIORITY); m2.setPriority(Thread.MAX_PRIORITY); m1.start(); m2.start(); } } Synchronization • When two or more threads need access to a shared resource, they need some way to ensure that the resource will be used by only one thread at a time. The process by which this is achieved is called synchronization. • Key to synchronization is the concept of the monitor (also called a semaphore) • . A monitor is an object that is used as a mutually exclusive lock, or mutex. • Only one thread can own a monitor at a given time. • When a thread acquires a lock, it is said to have entered the monitor. • All other threads attempting to enter the locked monitor will be suspended until the first • thread exits the monitor. These other threads are said to be waiting for the monitor. Understanding the problem without Synchronization • Class Table • { void printTable(int n) • {//method not synchronized • for(int i=1;i<=5;i++) • { System.out.println(n*i); • try{ Thread.sleep(400); } • catch(Exception e){System.out.println(e); • } } } } • class MyThread1 extends Thread • { Table t; • MyThread1(Table t) • { this.t=t; } • public void run() • { t.printTable(5); } } • class MyThread2 extends Thread • { Table t; • MyThread2(Table t) • { this.t=t; } • public void run() • { t.printTable(100); } } • class TestSynchronization1 • { public static void main(String args[]) • { Table obj = new Table();//only one object • MyThread1 t1=new MyThread1(obj); • MyThread2 t2=new MyThread2(obj); • t1.start(); • t2.start(); • } } • Output: • 5 • 100 • 10 • 200 • 15 • 300 • 20 • 400 • 25 • 500 Java synchronized method
• If you declare any method as synchronized, it
is known as synchronized method. • Synchronized method is used to lock an object for any shared resource. • When a thread invokes a synchronized method, it automatically acquires the lock for that object and releases it when the thread completes its task. • class Table • { synchronized void printTable(int n) • {//synchronized method • for(int i=1;i<=5;i++) • { System.out.println(n*i); • try{ Thread.sleep(400); • }catch(Exception e) • {System.out.println(e); • } } } } • class MyThread1 extends Thread • { Table t; • MyThread1(Table t) • { this.t=t; } • public void run() • { t.printTable(5); } } • class MyThread2 extends Thread • { Table t; • MyThread2(Table t) • { this.t=t; } • public void run() • { t.printTable(100); } } • public class TestSynchronization2 • { public static void main(String args[]) • { Table obj = new Table();//only one object MyThread 1 t1=new MyThread1(obj); • MyThread2 t2=new MyThread2(obj); • t1.start(); • t2.start(); • } } • Output: • 5 • 10 • 15 • 20 • 25 • 100 • 200 • 300 • 400 • 500 Inter-thread communication • Inter-thread communication or Co-operation is all about allowing synchronized threads to communicate with each other. • It is implemented by following methods of Object class: • wait() • notify() • notifyAll() • wait() tells calling thread to give up monitor and go to sleep until some other thread enters the same monitor and call notify. • notify() wakes up a thread that called wait() on same object. • notifyAll() wakes up all the thread that called wait() on same object. • class Customer • { int amount=10000; • synchronized void withdraw(int amount) • { System.out.println("going to withdraw..."); • if(this.amount<amount) • { System.out.println("Less balance; waiting for deposit..."); • try{wait();} • catch(Exception e){} • } • this.amount-=amount; • System.out.println("withdraw completed..."); } • synchronized void deposit(int amount) • { System.out.println("going to deposit..."); • this.amount+=amount; • System.out.println("deposit completed... "); • notify(); } } • class Test{ • public static void main(String args[]){ • final Customer c=new Customer(); • new Thread(){ • public void run(){c.withdraw(15000);} • }.start(); • new Thread(){ • public void run(){c.deposit(10000);} • }.start(); • • }} • Output: • going to withdraw... • Less balance; waiting for deposit... • going to deposit... • deposit completed... • withdraw completed Deadlock • Deadlock in java is a part of multithreading. Deadlock can occur in a situation when a thread is waiting for an object lock, that is acquired by another thread and second thread is waiting for an object lock that is acquired by first thread. Since, both threads are waiting for each other to release the lock, the condition is called deadlock. • public class TestDeadlockExample1 • { public static void main(String[] args) • { final String resource1 = "ratan jaiswal"; • final String resource2 = "vimal jaiswal"; • // t1 tries to lock resource1 then resource2 • Thread t1 = new Thread(); • { public void run() • { synchronized (resource1) • { System.out.println("Thread 1: locked resource 1"); t ry { Thread.sleep(100);} • catch (Exception e) {} • synchronized (resource2) • { System.out.println("Thread 1: locked resource 2"); } } } }; • // t2 tries to lock resource2 then resource1 • Thread t2 = new Thread() • { public void run() • { synchronized (resource2) { System.out.println("Thread 2: locked resource 2"); try { Thread.sleep(100); } catch (Exception e) {} synchronized (resource1) { System.out.println("Thread 2: locked resource 1");
} } } }; t1.start(); t2.start(); } } Output: Thread 1: locked resource 1 Thread 2: locked resource 2 Stop() • public class CounterThread implements Runnable { • • private int counter = 0; • • @Override • public void run() { • for (int i=0; i<10; i++) { • counter++; • System.out.println("Counter is :" + counter + " --- Current time is:" + new Date()); • try { • Thread.sleep(500); • if (counter == 5) { • Thread.currentThread().stop(); • } • } catch (InterruptedException e) { • e.printStackTrace(); • } • } • } • • public int getCounter() { • return counter; • } • } • package com.reallybigindex.java.threads; • • public class CounterDemo { • • public static void main(String[] args) { • • CounterThread counter = new CounterThread(); • Thread t1 = new Thread(counter); • t1.start(); • • for (int i = 0; i<10; i++) { • try { • System.out.println("Main thread: " + i); • Thread.sleep(1000); • if (i == 5) { • t1.resume(); • } • } catch (Exception e) { • e.printStackTrace(); • } • } • } • } • Suspend() and resume() package com.reallybigindex.java.threads; • • import java.util.Date; • • public class CounterThread implements Runnable { • • private int counter = 0; • • • public void run() { • for (int i=0; i<10; i++) { • counter++; • System.out.println("Counter is :" + counter + " --- Current time is:" + new Date()); • try { • Thread.sleep(500); • if (counter == 5) { • Thread.currentThread().suspend(); • } • } catch (InterruptedException e) { • e.printStackTrace(); • } • } • } • • public int getCounter() { • return counter; • } • }