Você está na página 1de 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 { // The producer thread class


MyData data;
public Producer(MyData data) {
this.data=data;
}

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 { // The producer thread class


MyData data;
public Producer(MyData data) {
this.data=data;
}

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) { }
}
}
}

- 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();
}
}

Você também pode gostar