Multi Threading

  • November 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Multi Threading as PDF for free.

More details

  • Words: 2,015
  • Pages: 13
Important Topics 1

What is a Thread?

2

Why Multiple Threads

3

Java’s Built-in Thread Support.

4

Thread Priority.

5

Thread Scheduler.

6

Rules that will determine when the Thread Scheduler will switch Threads.

7

start () and run ().

8

setPriority () and getPriority ()

9

setName() and getName ()

10

currentThread () -getting a handle to the main thread

11

Thread Constructors

12

Thread class and Runnable Interface

13

isAlive ()

14

Two ways of creating Threads

15

Using constructors instead of writing in the main method.

16

sleep() – With both the ways

17

using yield ()

18

creating multiple Threads

19

join () – using it both the ways.

20

suspend (), resume (), stop () – reason why it is not being used.

21

Synchronization

22

The monitor model for synchronization

23

Releasing the lock flag

24

Daemon & user Threads

25

ThreadGroup

26

Creating threads in a ThreadGroup

27

Methods that operate on a ThreadGroup –

28

Access Restriction Methods - setMaxPriority ()

Synchronization -

When two or more threads need to access 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 a monitor. A method is an object that is used as a mutually exclusive lock. 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 exists the monitor. The other threads are said to be waiting to acquire lock on the monitor

-

In java, synchronization is easy because each object has its own explicit monitor that is automatically entered when one of the object’s synchronized methods is called. Once a thread is inside a synchronized method, no other thread can call any other synchronized method on the same object. To enter an object’s monitor, just call a method that has been modified with the synchronized keyword. The general form of synchronized method is: synchronized method() { statements inside the method; }

-

When a thread enters the synchronized method, it is said acquire the lock flag (key) to the object and all the other threads will have to wait till the time, it releases the lock flag. Therefore it is important for the thread to hand over the lock flag when it is no longer required.

-

The lock flag is given back to its object automatically. When the thread that holds the lock passes the end of the synchronized code () for which the lock was obtained, the lock is released. Java technology ensures that the lock is always returned automatically, even if an encountered exception or break statement transfers code execution out of a synchronized block

An Example of why Synchronized block is required: class Callme { synchronized void call(String msg) { System.out.print("[" + msg); try { Thread.sleep(1000); } catch (Exception e) {} System.out.println("]"); } } class caller implements Runnable { String msg; Callme target;

public caller(Callme t, String s) { target = t; msg = s; new Thread(this).start(); } public void run() { target.call(msg); } } class Synch1 { public static void main(String args[]) { Callme target = new Callme(); new caller(target, "Hello"); new caller(target, "Synchronized"); new caller(target, "World"); new caller(target, "Finally"); } }

Another Example of how yield () works

-

class WellBehavedPrintThread implements Runnable { String str; public WellBehavedPrintThread(String str) { this.str = str; } public void run() { for (int i = 0;i<100;i++) { System.out.print (str); //Thread.currentThread().yield(); } } } class ConcurrencyTest2 { public static void main (String Args[]) { new Thread(new WellBehavedPrintThread("A")).start(); new Thread(new WellBehavedPrintThread("B")).start(); new Thread(new WellBehavedPrintThread("C")).start(); new Thread(new WellBehavedPrintThread("D")).start(); } }

-

In the earlier example, there was only class and we were creating multiple threads from that class and saw how synchronization could be done. Now let’s take another example, wherein,

there is a XYS class in which there are two methods store () and load () and it has a private variable which will be inserted by the store method and taken away by the load method. There are now two different classes class Producer that will call the store () and class Consumer that will call the load () method. Remember that both the classes will access the same object of the XYZ class. Now the producer will keep on storing numbers and consumer will keep on taking numbers. Also both the threads will be sleeping after they have used the methods. What we want is that Producer should store only one value and the Consumer will have to take that value only once and all the values stored by the Producer should be taken also. class MyData { private int Data; public void store(int Data) { this.Data=Data; } public int load() { return this.Data; } } class Main { // This class is used to set things in motion. public static void main(String argv[]) { MyData data = new MyData(); new Thread(new Producer(data)).start(); new Thread(new Consumer(data)).start(); } } class Producer implements Runnable { MyData data; public Producer(MyData data) { this.data=data; }

// The producer thread class

public void run() { int i; for (i=0;;i++) { data.store(i); System.out.println ("Producer: "+i); try { // doze off for a random time (0 to 0.5 sec) Thread.sleep ((int) (Math.random()*500)); } catch (InterruptedException e) { } } } } class Consumer implements Runnable { // The consumer thread MyData data; public Consumer(MyData data) { this.data=data; }

public void run() { for (;;) { System.out.println ("Consumer: "+data.load()); try { // doze off for a random time (0 to 0.5 sec) Thread.sleep ((int) (Math.random()*500)); } catch (InterruptedException e) { } } } }

-

We can achieve the above kind of our result with the following code where both the methods are synchronized.

class MyData { private int Data; private boolean Ready; private boolean Taken; public MyData() { Ready=false; Taken=true; } public synchronized void store(int Data) { while (!Taken); this.Data=Data; Taken=false; Ready=true; } public synchronized int load() { while (!Ready); Ready=false; Taken=true; return this.Data; } } class Main3 { // This class is used to set things in motion. public static void main(String argv[]) { MyData data = new MyData(); new Thread(new Producer(data)).start(); new Thread(new Consumer(data)).start(); } } class Producer implements Runnable { MyData data; public Producer(MyData data) { this.data=data; } public void run() { int i;

// The producer thread class

for (i=0;;i++) { data.store(i); System.out.println ("Producer: "+i); try { // doze off for a random time (0 to 0.5 sec) Thread.sleep ((int) (Math.random()*500)); } catch (InterruptedException e) { } } } } class Consumer implements Runnable { // The consumer thread MyData data; public Consumer(MyData data) { this.data=data; } public void run() { for (;;) { System.out.println ("Consumer: "+data.load()); try { // doze off for a random time (0 to 0.5 sec) Thread.sleep ((int) (Math.random()*500)); } catch (InterruptedException e) { } } } }

-

Although threads for doing individual things, many a times, we want one thread to inform others, when some of his work has been finished. This is done by the wait (), notify () and notifyAll () methods. Let’s take a example of a Stock Class which has addStock () which will be used by the producer class to add stock and getStock () which will be used by the consumer class to get the stock. The Stock class should also maintain the balance of the stock at any particular point of time. The following code explains the same

class Consumer extends Thread //implements Runnable { Stock c; Thread t; Consumer(Stock c) { this.c = c; //t.new Thread(this,"Consumer Thread"); start(); //t.start(); } public void run() { while (true) {

try { t.sleep(750); } catch(InterruptedException e) {} c.getStock((int)(Math.random()*100)); } } } class Producer extends Thread//implements Runnable { Stock s; Thread t; Producer (Stock s) { this.s = s; //t.new Thread(this,"Producer Thread"); start(); //t.start(); } public void run() { while (true) { try { t.sleep(750); } catch(InterruptedException e) {} s.addStock((int)(Math.random()*100)); } } } class Stock { int goods=0; public synchronized void addStock(int i) { goods = goods+i; System.out.println("Stock added : "+i); System.out.println("Present Stock : "+goods); notify();

} public synchronized void getStock(int j) { while (true) { if(goods>=j) { goods = goods - j; System.out.println("Stock taken away : "+j); System.out.println("Present Stock: "+goods); break; } else { System.out.println("Stock not enough..."); System.out.println("Waiting for stock to come via producer "); try { wait(); } catch(InterruptedException e) {} } } } public static void main (String arg[]) { Stock j = new Stock(); Producer p = new Producer(j); Consumer c = new Consumer(j); try { Thread.sleep(10000); //p.t.join(); //c.t.join(); System.out.println("Thread Stopped"); } catch(InterruptedException e) {} System.exit(0); } }

-

This is another Example of multiple threads of Producers and Consumers acting on a single Class.

import java.util.Vector; class SyncExample

{ public static void main(String arg[]) { SyncStack stack = new SyncStack(); Producer1 p1 = new Producer1(stack); Thread pT1 = new Thread(p1); pT1.start(); Producer1 p2 = new Producer1(stack); Thread pT2 = new Thread(p2); pT2.start(); Consumer1 c1 = new Consumer1(stack); Thread cT1 = new Thread(c1); cT1.start(); Consumer1 c2 = new Consumer1(stack); Thread cT2 = new Thread(c2); cT2.start(); try { Thread.sleep(1000); System.out.println("Thread Stopped"); } catch(InterruptedException e) {} System.exit(0); } } class Producer1 implements Runnable { SyncStack thestack; int num; static int counter=1; Producer1(SyncStack s) { thestack = s; num = counter++; } public void run() { char c; for (int i = 0 ;i < 200 ;i++ ) { c = ((char)(Math.random()*26+'A')); thestack.push(c); System.out.println("Producer " + num + ": " + c);

try { Thread.sleep((int)(Math.random() * 300)); } catch(InterruptedException e) {} } } } class Consumer1 implements Runnable { SyncStack thestack; int num; static int counter=1; Consumer1(SyncStack s) { thestack = s; num = counter++; } public void run() { char m; for (int i = 0 ;i < 200 ;i++ ) { m = thestack.pop(); System.out.println("Consumer " + num + ": " + m); try { Thread.sleep((int)(Math.random() * 300)); } catch(InterruptedException e) {} } } } class SyncStack { Vector v = new Vector(400,200); public synchronized char pop() { char c; while (v.size()==0) { try { this.wait(); } catch(InterruptedException e)

{} } c = ((Character)v.remove(v.size()-1)).charValue(); return c; } public synchronized void push(char c) { this.notify(); Character c1 = new Character(c); v.addElement(c1); } }

-

Another Example of using NotifyAll, wherein there is one producer and multiple Consumers. If one uses notify (), then there is no guarantee who will be notified and incase of using notifyAll (), then all the threads will be notified and then it depends on the Thread Schedule to schedule them.

class Producer extends Thread { Queue queue; Producer(Queue queue) { this.queue = queue; } public void run() { int i = 0; while(true) { queue.add(i++); } } } class Consumer extends Thread { String str; Queue queue; Consumer(String str, Queue queue) { this.str = str; this.queue = queue; } public void run() { while(true) { System.out.println(str + ": " + queue.remove()); } } } class Queue { private final static int SIZE = 10; int array[] = new int[SIZE]; int r = 0;

int w = 0; int count = 0; synchronized void add(int i) { // Wait while the queue is full while(count == SIZE) { try { wait(); } catch(InterruptedException ie) { ie.printStackTrace(); System.exit(0); } } // Add data to array and adjust write pointer array[w++] = i; if(w >= SIZE) w = 0; // Increment count ++count; // Notify waiting threads notifyAll(); } synchronized int remove() { // Wait while the queue is empty while(count == 0) { try { wait(); } catch(InterruptedException ie) { ie.printStackTrace(); System.exit(0); } } // Read data from array and adjust read pointer int element = array[r++]; if(r >= SIZE) r = 0; // Decrement count --count; // Notify waiting threads notifyAll(); // Return element from array return element; } }

class ProducerConsumers { public static void main(String args[]) { Queue queue = new Queue(); new Producer(queue).start(); new Consumer("ConsumerA", queue).start(); new Consumer("ConsumerB", queue).start(); new Consumer("ConsumerC", queue).start(); } }

-

Related Documents

Multi Threading
November 2019 31
Multi Threading
November 2019 31
Multi Threading
November 2019 22
Multi Threading 3
October 2019 32
Multi Threading Overview
November 2019 20