cpan322-lec6 Download

Transcript
CPAN322 Java Application Programming
Lecture #6: Multithreading
Multithreading is a programming technique for executing multiple tasks
concurrently. Java has built-in support for multithreading and provides many
standard library classes for creating and managing threads.
Threads are executed and monitored by the Java threads scheduler. The
scheduling priority enables threads with high priority to complete execution
before threads with lower priority can start running. Threads can be
synchronized to prevent corruption; this method is called shared resources.
A thread is a program unit that runs independently for the other parts of the
program. Java has built-in multithreading capability that allows us to execute
more than one task simultaneously. Java's automatic garbage collector is an
example of multithreading. It runs as a separate thread to reclaim any unused
memory taken by objects that are no longer referenced in the application.
Using threads enables, for example, an applet to do something in the
background while the browser is doing its job. We can use threads in our
application so that certain tasks such as printing are executed in the background
while the user is performing another task(s).
Java support for multithreading is platform dependent. On computers with single
processors, Java supports multithreading by slicing the processor time among all
the running tasks. On computers with multiple processors, Java may assign
different threads to different processors, or slice the possessors times among all
running tasks .
To implement a thread perform the following steps::




Implement a class that extends the Thread class. Java doesn't support
multiple inheritance. Therefore, if your class is already extending another
class, then you can implement the Runnable interface.
Implement a method called run , and code your task into this method.
When the thread is started, the run method will be called.
Create an object of the implemented class.
Call start method of the newly created object to start the thread.
The following example shows how to support multithreading by extending the
Thread class:
1
class myThread extends Thread
{
myThread()
{}
public void run()
{
// code your task here
}
}
After that you can create and start a new thread object as follows:
myThread mt = new myThread();
mt.start();
Support multithreading by implementing the Runnable interface is shown in the
following example:
class myThread implements Runnable
{
myThread()
{}
public void run()
{
// code your task here
}
}
Then you can create and start a new thread object as follows:
myThread mt = new myThread();
Thread thread=new Thread(mt);
thread.start();
Some of the methods of the class Thread are:



activeCount: Returns the number of active threads in the current thread's
thread group.
CurrentThread: Returns a reference to the currently executing thread
object.
enumerate: Copies into the specified array every active thread in the
current thread's thread group and its subgroups.
2














getName: Returns the thread's name.
getPriority: Returns the thread's priority.
GetThreadGroup: Returns the thread group to which this thread belongs
isAlive: Tests if the thread is alive.
setName: Changes the name of the thread.
SetPriority: Changes the priority of the thread.
sleep: Causes the currently executing thread to sleep (temporarily cease
execution) for the specified number of milliseconds. When you send a
thread for sleep.
start: Causes the thread to begin execution; the Java Virtual Machine
calls the run method of this thread.
yield: Causes the currently executing thread object to temporarily pause
and allow other threads to execute.
interrupt: Interrupts this thread. When a sleeping thread is interrupted, an
InterruptedException is generated.
Interrupted: Tests whether the current thread has been interrupted.
wait: Causes current thread to wait until another thread invokes the notify
notify method or notifyAll method for this object
notifyAll: Wakes up all threads that are waiting on this object's monitor. A
thread waits on an object's monitor by calling one of the wait methods.
notify: Wakes up a single thread that is waiting on this object's monitor
wait, notify and notifyAll methods are inherited from the Object class.
The Runnable interface has only one method called run. Starting a thread that
implements the Runnable interface causes the run method to be executed.
A thread is terminated when its run method terminates. To terminate a thread
we use interrupt method. You should check in run method if the thread is
interrupted and perform any necessary clean and exit run.
To group multithreads in the same application, we use the ThreadGroup class.
This class has many methods for creating and managing a group of threads. For
example:
String groupName="MyGroup ";
ThreadGroup group=new ThreadGroup(groupName);
Thread newThread=new Thread(group,mt);
3
Following are some of the methods of ThreadGroup class:






activeCount: Returns an estimate of the number of active threads in this
thread group.
enumerate: Copies into the specified array every active thread in this
thread group and its subgroups.
getMaxPriority: Returns the maximum priority of this thread group.
getName: Returns the name of this thread group.
getParent: Returns the parent of this thread group.
list: Prints information about this thread group to the standard output.
When a thread runs for the benefit of another thread, it is called daemon thread.
Daemon threads run in the background and don't prevent the program from
terminating. The method setDaemon(true) is used on a thread to mark it as a
daemon thread. The method isDaemon is used to determine if a thread is
daemon.
The Life cycle of a thread:
When the thread is created it will be in the born state. When the start method of
this thread is called, it enters the ready state (runnable state).
A thread with high priority enters the running state when the system assigns a
processor to this thread.
A thread enters the dead state when its run method finishes execution or
terminates for any reason. A dead thread will be disposed by the system.
A thread enters the blocked state when it issues an Input/Output request. A
blocked thread cannot use a processor even if there is one available until the I/o
request it made is finished. The blocked thread then enters the ready state
again.
A running thread enters the sleeping state when its sleep method is called. A
sleeping thread cannot use a processor even if there is one available. After the
specified sleeping time expires, the sleeping thread enters the ready state again.
When the method wait of a running thread is called, it causes the thread to enter
the waiting state. A thread in the waiting state enters the ready state when it is
notified by another associated thread.
4
When the method yield of a running thread is called, it causes the thread to
enter the ready state allowing other threads to execute.
Threads priority and thread scheduling:
The Java thread scheduler monitors all threads and keep all the threads of high
priority running. The thread scheduler runs each thread for a short amount of
time called a time slice. The thread scheduler then activate another thread from
the available runnable threads .
The thread scheduler run threads based on their priority. Every Java thread can
have priority in the range Thread.MIN_PRIORITY , and
Thread.MAX_PRIORITY with associated values between 1 and 10. The default
priority is Thread.NORM_PRIORITY with an associated value of 5.
Within threads of the same priority, the Java scheduler slice the processor time
to enable all of them to run simultaneously.
The priority of a thread can be adjusted using setPriority method by passing a
value between 1 and 10. Calling the yeild method of a thread enables other
threads to run.
Threads synchronization:
The Java's keyword synchronize is sued to put a lock around a particular
method so that one thread can execute this method at any time. All other
threads that are trying to execute this method must wait
.
If a thread execution in a synchronized block determines that it cannot proceed
execution for any reason, then it enters in the waiting state allowing other
threads to run. When a thread finishes executing a synchronized block, it can
notify other waiting threads that the execution is completed.
You have to be careful not to lock your entire application, by making all the
methods synchronized. Your application will not be multithreaded anymore
because only one thread can run at a time.
5
A deadlock occurs when no thread can proceed because each thread is waiting
for another thread to finish performing certain task.
Threads can have producer/ consumer relationship. According to the
producer/ consumer module, two synchronized threads cooperate together to
produce and consume a shared data recourse. The consumer thread must wait
for the result of the producer thread execution and the producer has to wait for
result to be consumed by the the consumer thread.
Examples:
Ex1:
In this example we will have two threads running simultaneously. We will support
multithreading by extending the Thread class. The first class will simply print the
string T1 100 times and the second thread will print the string T2 100 times.
class myThread extends Thread
{
private String arg;
public myThread(String a)
{arg=a;
}
public void run()
{
for(int i=0;i<100;i++)
6
System.out.print(arg);
}
}
public class threadTest
{
public static void main(String args[])
{
myThread mt1=new myThread(" T1 ");
myThread mt2=new myThread(" T2 ");
mt1.start();
mt2.start();
}
}
Ex2:
This example is similar to Ex1 except that multithreading will be supported by
implementing the Runnable interface.
class myThread implements Runnable
{
private String arg;
public myThread(String a)
{arg=a;
}
public void run()
{
for(int i=0;i<100;i++)
System.out.print(arg);
}
}
public class threadTestR
{
public static void main(String args[])
{
Thread mt1=new Thread(new myThread(" T1 "));
Thread mt2=new Thread(new myThread(" T2 "));
7
mt1.start();
mt2.start();
}
}
Ex3:threadsDetails.java
In this example we will track the status of 4 running threads:
class MyThread extends Thread
{
private int nsleep;
private Thread t;
public MyThread(String name )
{
super(name);
System.out.println(name+" is in ready state");
nsleep=(int )(Math.random()*50);
t=new Thread();
}
public void run()
{
System.out.println(getName()+ " has started");
System.out.println(getName() +" sleep time "+nsleep);
try
{
int status=0;
t.sleep(nsleep);
for(int j=0;j<100;j++)
{
8
if(!currentThread().interrupted())
System.out.println(getName()+ " is running");
}
System.out.println(getName()+"has died");
}
catch(InterruptedException e)
{
System.out.println(e.toString();
}
}
}
public class threadsDetails
{
private static MyThread td[];
public static void main(String args[])
{
td=new MyThread[2];
for(int i=0;i<2;i++)
{
td[i]=new MyThread("Thread"+(i+1));
td[i].start();
}
}
}
Ex4:clock.java
In this example we will use a thread to display the time updated every second in
the application frame window:
9
import java.awt.*;
import javax.swing.*;
class clock extends JFrame implements Runnable
{
private JLabel time;
public clock()
{
super ("Timer ");
setSize(300,300);
setVisible(true);
}
public void run()
{
try
{
while (true)
{
Thread.sleep(1000);
repaint();
}
}
catch(InterruptedException e)
{}
}
public void paint(Graphics g)
{
super.paint(g);
g.drawString(new java.util.Date().toString(),50,100);
}
public static void main(String args[])
{
10
clock cApp=new clock();
Thread thread=new Thread(cApp);
thread.start();
}
}
Ex5:TreadedDrawing.java
In this example we will be using multithreading to fill three rectangles in one
frame simultaneously.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ThreadedDrawing extends JFrame
{
// create threads of the 3 ThreadBar objects
Thread[] m_thread = new Thread[3];
Runnable[] runnable = new Runnable[3];
public ThreadedDrawing()
{
super ("Multithreading Example");
Container c = getContentPane();
c.setLayout(new GridLayout(3,1));
runnable[0] = new ThreadBar(Color.red);
runnable[1] = new ThreadBar(Color.blue);
runnable[2] = new ThreadBar(Color.green);
c.add((JComponent)runnable[0]);
c.add((JComponent)runnable[1]);
c.add((JComponent)runnable[2]);
m_thread[0] = new Thread(runnable[0]);
m_thread[1] = new Thread(runnable[1]);
m_thread[2] = new Thread(runnable[2]);
11
m_thread[0].start();
m_thread[1].start();
m_thread[2].start();
setSize(300,300);
setResizable(false);
setVisible(true);
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
}
public static void main(String args[])
{
new ThreadedDrawing();
}
/*
private class to fill a rectangle with certain color.
*/
private class ThreadBar extends JComponent implements Runnable
{
// filling width
private int fillWidth = 0;
private Color currentColor;
public ThreadBar(Color color)
{
currentColor=color;
}
12
public void addNotify()
{
super.addNotify();
}
public void paintComponent(Graphics g)
{
Dimension s = getSize();
g.setColor(Color.black);
g.drawRect(5,5, s.width-10, s.height-10);
g.setColor(currentColor);
g.fillRect(6,6, fillWidth, s.height-11);
}
public void run()
{
/*
Make sure the rectangle is filled within certain width
*/
while (fillWidth< 285)
{
// increment the filling width
fillWidth+=5;
repaint();
try
{
Thread.sleep((long)(Math.random()*500));
}
catch (InterruptException e)
{
JOptionPane.showMessageDialog(null,e.toString());
}
}
}
13
}
}
Ex6:SynchronizationEx.java
In this example we have an account object and two threads trying to access and
change the balance of this account.
The class Account defines the attributes and methods of the shared account. The
methods that access/change the account balance must be synchronized to
prevent data corruption.
The two threads are the transaction thread and the balance thread. The
transaction thread tries to update the value of the account balance by randomly
depositing or withdrawing a certain amount of money. The balance account tries
to retrieve the value of the balance. To prevent any lost of data, or duplicated
values, one thread has to access the shared account after the other. When the
transaction thread accesses the account balance, the balance thread must wait
until the transaction thread finishes updating the balance value. When the
balance thread accesses the account balance, the transaction thread must be in
a waiting state. The variable is writable is defined in the Account class for this
reason.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.text.*;
public class SynchronizationEx {
public static void main(String[] args)
{
14
/*
create an account object to be shared by the two threads
*/
Account account=new Account(1000);
// create a balance tracking thread
Thread bThread=new Thread(new BalanceThread(account),"Balance
thread");
// create a transaction tracking thread
Thread tThread =new Thread(new
TransactionThread(account),"Transaction thread");
bThread.start();
tThread.start();
}
}
/*
Class Account represent the shared account
*/
class Account
{
/*
The variable writable is used to protect the balance from beeing accessed
by more than one thread at any time.
If the transaction thread is accessing the balance then the balance thread
must wait, and vise versa
*/
private boolean writeable=false;
// the account balance
private double balance;
public Account(int balance)
{
this.balance=balance;
}
public synchronized void addToBalance(double bl)
{
while(!writeable)
{
try{
wait();
}
catch(InterruptedException e)
15
{
JOptionPane.showMessageDialog(null,e.toString());
}
}
balance+=bl;
writeable=false;
notify();
}
public synchronized double getBalance()
{
while(writeable)
{
try{
wait();
}
catch(InterruptedException e)
{
JOptionPane.showMessageDialog(null,e.toString());
}
}
writeable=true;
notify();
return balance;
}
}
/*
The transaction thread will be used to deposit to or withdraw from the
shared account.
*/
class TransactionThread extends JFrame implements Runnable
{
private Account pdata;
double maxbalance=0.0;
private JTextArea ta;
private Container c;
private DecimalFormat df;
16
public TransactionThread(Account d)
{
super("Transaction Tracking Frame");
pdata=d;
c=getContentPane();
ta=new JTextArea();
c.add(new JScrollPane(ta));
df=new DecimalFormat("0.00");
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e)
{
System.exit(0);
}});
setSize(350,300);
setLocation(360,20);
setVisible(true);
}
public void run()
{
for(int i=0;i<5;i++)
{
try{
Thread.sleep((int)(Math.random()*1000));
}
catch(InterruptedException e)
{}
/*
The transaction amount is calculated randomly
*/
double bal=Math.random()*1000;
/*
The transaction type is determied randomly. It can be either deposit or
withdraw.
*/
int status=(int)(Math.random()*10);
if(status<5)
{
pdata.addToBalance(bal);
ta.append("amount added by "+Thread.currentThread().getName()+"
"+df.format(bal)+"\n");
}
17
else
{
pdata.addToBalance(-bal);
ta.append("amount subtracted by "+Thread.currentThread().getName()+"
"+df.format(bal)+"\n");
}
}
ta.append(Thread.currentThread().getName()+" has finished prforming
transaction"+"\n");
}
}
/*
The balance thread will be used to retreive the balance from the shared
account
*/
class BalanceThread extends JFrame implements Runnable
{
private Account cdata;
double maxbalance=0.0;
private JTextArea ta;
private Container c;
private DecimalFormat df;
public BalanceThread(Account d)
{
super("Balance Tracking Frame");
cdata=d;
c=getContentPane();
ta=new JTextArea();
c.add(new JScrollPane(ta));
df=new DecimalFormat("0.00");
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e)
{
System.exit(0);
}});
setSize(350,300);
setLocation(10,20);
setVisible(true);
}
public void run()
{
18
for(int j=0;j<6;j++)
{
try
{
Thread.sleep((int)(Math.random()*1000));
}
catch(InterruptedException e)
{
}
// get the balance from the shared account
maxbalance=cdata.getBalance();
ta.append(Thread.currentThread().getName()+" determined that balance is
"+df.format(maxbalance)+"\n");
}
ta.append(Thread.currentThread().getName()+" has finished retrieving the
balance");
}
}
19
Similar
Document
Document
From controller to threads
From controller to threads