Threads
Мultiprocessing- две или повече програми, които се изпълняват "видимо" конкурентно под контрола на операционната система. Програмите нямат никаква връзка помежду си освен факта че се стартират и изпълняват едновременно. |
Прилага се от операционната система и в рамките на програмата не е необходимо да се взимат никакви мерки.
Multithreading - две или повече задачи, които се изпълняват "видимо" паралелно в рамките на една и съща програма. Понякога се наричат "леки" (lightweight ) процеси |
Въпреки че се нуждае от поддръжката на операционната система, се прилага и изпълнява от самата програма. необходимо е специално проектиране и планиране на програмата.
Нишките в Java са обекти от клас Thread който е част от пакета java.lang.
При създаването на нова нишка е необходимо да се предефинира методът run(), като цялата функционалност на нишката се вгражда в този метод.
Методът run() може да вика други методи.
Нишката се стартира чрез извикването на start() метода на съответния обект.
Методът start() от своя страна вика run() метода и се грижи за изпълняването на всички допълнителни необходими задачи.
Нито един от тези методи няма параметри.
В една програма могат да се използват много различни Thread класа и много различни обекти от един и същи Thread клас.
Всеки от тези класове има свой собствен run() метод, който е независим от run() методите на останалите класове
Thread()
Allocates a new Thread
object. |
Thread(Runnable target) Allocates a new Thread
object. |
Thread(Runnable target, String name) Allocates a new Thread
object. |
Thread(String name) Allocates a new Thread
object. |
public static Thread
currentThread()
Returns a reference to the currently executing thread object. |
public final
String getName()
Returns this thread's name. |
public final void setName(String name) Changes the name of this thread to be equal to the argument name . |
o Класът java. lang.
Thread позволява
създаването на нови нишки (threads) |
Под
- клас на
Thread
o Метод 1 : подклас на Thread class Proc1 extends
Thread { |
Наследяване
на Runnable
o Метод 2 : клас наследяващ Runnable class Proc2 implements
Runnable { |
Кой
метод да се
избере ?
o Метод 1 : под-клас на Thread public class MyThreadApplet extends Applet implements Runnable {}
|
Състояния
Състоянието на нишката показва какво в момента тя върши и какво е в състояние да извърши. Тя може да бъде в 4 състояния: нова ( New ), работеща (Runnable), неработеща,блокирана(Blocked) и завършена (Dead ).
За всяко влизане в неработещо състояние, съществува специфичен и различен от останалите начин за връщане в работещо състояние. Всяко връщане работи само за съответния начин на влизане. Например ако тя е блокирана със sleep() връщането и в работещо състояние може да стане само след изтичането на определения брой милисекунди. Извикването на метода resume() няма да има ефект. |
Metod isAlive()
Класът Thread притежава метод isAlive(), който се използва за проверка на състоянието на нишката:
Metod getState()
Release 5.0 Въвежда
метода
Thread.getState()
. При извикването му се връща
една от следните
Thread.State
стойности
:
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED
Прост
пример - нишка работеща през цялото време:
//: CounterA.java // Using the Runnable interface to turn the // main class into a thread. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class CounterA extends JPanel implements Runnable { private int count = 0; private boolean runFlag = true; private Thread selfThread = null; private Button onOff = new Button("Stop"), start = new Button("Start"); private TextField t = new TextField(10); private Label l = new Label("Thread: no Thread counter yet"); public void init() { add(t); start.addActionListener(new StartL()); add(start); onOff.addActionListener(new OnOffL()); add(onOff); add(l); } public void run() { while (true) { try { Thread.sleep(100); } catch (InterruptedException e){} if(runFlag) { t.setText(Integer.toString(count++)); l.setText("Thread: "+selfThread.getName()); } } } class StartL implements ActionListener { public void actionPerformed(ActionEvent e) { if(selfThread == null){ selfThread = new Thread(CounterA.this); selfThread.start(); } runFlag = true; } } class OnOffL implements ActionListener { public void actionPerformed(ActionEvent e) { runFlag = false; } } public static void main(String[] args) { CounterA cnt = new CounterA(); JFrame frame = new JFrame("CounterA"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(cnt); frame.setSize(300,200); cnt.init(); frame.setVisible(true); } } |
//: CompteurA1.java // Using the Runnable interface to turn the // main class into a thread. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class CounterA1 extends JPanel implements Runnable { private int count = 0; private Thread selfThread = null; private Button stop = new Button("Stop"), start = new Button("Start"); private TextField t = new TextField(10); private Label l = new Label("Thread: no Thread counter yet"); private boolean runFlag=true; public void init() { add(t); add(l); start.addActionListener(new StartL()); add(start); stop.addActionListener(new StopL()); add(stop); } public void run() { while (runFlag) { try { Thread.sleep(100); } catch (InterruptedException e){} t.setText(Integer.toString(count++)); l.setText("Thread: "+selfThread.getName()); } selfThread = null; } class StartL implements ActionListener { public void actionPerformed(ActionEvent e) { if(selfThread == null){ selfThread = new Thread(CounterA1.this); runFlag=true; selfThread.start(); } } } class StopL implements ActionListener { public void actionPerformed(ActionEvent e) { if(selfThread != null) { // selfThread.stop(); deprecated runFlag =false; } } } public static void main(String[] args) { CounterA1 cnt = new CounterA1(); JFrame aFrame = new JFrame("CounterA1"); aFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); aFrame.add(cnt); aFrame.setSize(300,200); cnt.init(); aFrame.setVisible(true); } } |
//: CounterPT.java // If you separate your thread from the main // class, you can have as many threads as you want. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Ticker extends Thread { private Button b = new Button("Toggle"); private TextField t = new TextField(10); private int count = 0; private boolean runFlag = true; public Ticker(Container c) { b.addActionListener(new ToggleL()); JPanel p = new JPanel(); p.add(t); p.add(b); c.add(p); } class ToggleL implements ActionListener { public void actionPerformed(ActionEvent e) { runFlag = !runFlag; } } public void run() { while (true) { if(runFlag) t.setText(Integer.toString(count++)); try { sleep(100); } catch (InterruptedException e){} } } public void stp() { runFlag = false; } public void restart() { runFlag = true; } } public class CounterPT extends JPanel { private Button start = new Button("Start"); private Button stop = new Button("Stop"); private Button restart = new Button("Restart"); private boolean started = false; private Ticker[] s; private int size; public void init() { this.setLayout(new FlowLayout()); s = new Ticker[size]; for(int i = 0; i < s.length; i++) s[i] = new Ticker(this); start.addActionListener(new StartL()); add(start); stop.addActionListener(new StopL()); add(stop); restart.addActionListener(new RestartL()); add(restart); } class StartL implements ActionListener { public void actionPerformed(ActionEvent e) { if(!started) { started = true; for(int i = 0; i < s.length; i++) s[i].start(); } } } class StopL implements ActionListener{ public void actionPerformed(ActionEvent e) { for(int i=0;i<s.length;i++) s[i].stp(); } } class RestartL implements ActionListener{ public void actionPerformed(ActionEvent e){ for(int i=0; i< s.length; i++) s[i].restart(); } } public static void main(String[] args) { CounterPT cnt = new CounterPT(); cnt.size = (args.length == 0 ? 5 : Integer.parseInt(args[0])); JFrame aFrame = new JFrame("CounterPT"); aFrame.add(cnt); aFrame.setSize(200*(1+cnt.size/10), 500); aFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cnt.init(); aFrame.setVisible(true); } } |
Упражнение: Променете програмата, така че след достигане на определена стойност нишката да завършва изпълнението си. Въведете бутон "New", който да създава нови нишки-броячи. Въведете програмата в страница - ExerciseMT.html
Приоритети:
JVM управлява приоритетите чрез
алгоритъм известен като fixed
priority scheduling.
Всеки thread има приоритет (право да бъде стартирана преди другите). Приоритетите се представят с цели числа в диапазона от Thread.MAX_PRIORITY (10 - най-висок) до Thread.MIN_PRIORITY (1 - най-нисък). По подразбиране всяка нишка има същия приоритет като тази, която я създала. След като бъде създадена приоритета на нишката може да се променя с метода setPriority().
JVM използва два алгоритъма за превключване на нишките - време делене (Time sliced) известен като Round-Robin и изпреварващо (Pre-emptive). Как точно се управлява превключването зависи от платформата - използва се подхода използван в операционната система и е различен в различните случаи.
Round
- robin е метод ,
който балансира натоварването. Планировчикът
избира
ресурс, посочен от брояч към списъка от нишки, след
коет броячът се
увеличава и
ако е достигнат края, се завръща в началото на списъка.
Методът предотвратяване опасността от "starvation" на нишка, тъй като
всеки ресурс, подред се избира от Планировчика. Изпреварващо (Pre-emptive) превключване позволява прекъсването на изпълнението на дадена нишка в зависимост от готовността на нишка с по-висок приоритет. |
Един
прост пример
//: SimpleThread.java import java.util.*; // for Date import java.text.*; //for DateFormat and SimpleDateFormat public class SimpleThread extends Thread { private int countDown = 5; private String name; private static Date d = new Date( ); private static DateFormat df = new SimpleDateFormat("HH:mm:ss:SSS"); private volatile double db=0; // no optimization public SimpleThread(String nameP) { name = nameP; System.out.println("\t\tMaking " + name); } public void run() { d.setTime(System.currentTimeMillis( )); System.out.println(name + " start at " + df.format(d)); for( ;countDown>0; countDown--) { System.out.println("Thread " + name + "(" + countDown + ")"+ " priority -> " + getPriority() ); // An expensive, interruptible operation: for(int i = 1; i < 100000; i++) db = db + (Math.PI + Math.E) / (double)i; } System.out.println("Thread " + name + " end"); } public static void main(String[] args) { d.setTime(System.currentTimeMillis( )); System.out.println("\t\tmain start at " + df.format(d)); String nameA[]={"Nick", "Marie", "George", "Isabelle", "Pierre"}; for(int i = 0; i < 5; i++){ new SimpleThread(nameA[i]).start(); } System.out.println("\t\tAll Threads Started"); } } |
main start at 21:31:11:819 Making Nick Making Marie Nick start at 21:31:11:822 Thread Nick(5) priority -> 5 Making George Marie start at 21:31:11:822 Thread Marie(5) priority -> 5 Making Isabelle George start at 21:31:11:823 Thread George(5) priority -> 5 Making Pierre Isabelle start at 21:31:11:824 Thread Isabelle(5) priority -> 5 All Threads Started Pierre start at 21:31:11:825 Thread Pierre(5) priority -> 5 Thread Marie(4) priority -> 5 Thread Nick(4) priority -> 5 Thread George(4) priority -> 5 Thread Isabelle(4) priority -> 5 Thread Pierre(4) priority -> 5 Thread Marie(3) priority -> 5 Thread Nick(3) priority -> 5 Thread Isabelle(3) priority -> 5 Thread George(3) priority -> 5 Thread Pierre(3) priority -> 5 Thread Pierre(2) priority -> 5 Thread Marie(2) priority -> 5 Thread George(2) priority -> 5 Thread Isabelle(2) priority -> 5 Thread Nick(2) priority -> 5 Thread Pierre(1) priority -> 5 Thread Marie(1) priority -> 5 Thread George(1) priority -> 5 Thread Pierre end Thread George end Thread Marie end Thread Isabelle(1) priority -> 5 Thread Nick(1) priority -> 5 Thread Isabelle end Thread Nick end |
Пример с модификация на приоритета:
import
java.text.*; import java.util.*; //: SimpleThreadPr.java public class SimpleThreadPr extends Thread { private int countDown = 5; private String name; private static Date dt = new Date( ); private static DateFormat df = new SimpleDateFormat("HH:mm:ss:SSS"); private volatile double d=0; // no optimization public SimpleThreadPr(String name, int prior) { this.name = name; setPriority(prior); System.out.println("\t\tMaking " + name); } public void run() { dt.setTime(System.currentTimeMillis( )); System.out.println(name+"start at "+df.format(dt)+"pr -> "+getPriority()); for( ;countDown>0; countDown--) { // An expensive, interruptible operation: for(int i = 1; i < 100000; i++) d = d + (Math.PI + Math.E) / (double)i; System.out.println("Thread " + name + "(" + countDown + ")"+ " priority -> " + getPriority() ); } System.out.println("Thread " + name + " end"); } public static void main(String[] args) { String nameA[]={"Nick", "Marie", "George", "Isabelle", "Pierre","Rose","Salome"}; SimpleThreadPr st[] = new SimpleThreadPr[nameA.length]; for(int i = 0; i < nameA.length; i++) st[i] = new SimpleThreadPr(nameA[i],i<3?Thread.MAX_PRIORITY: Thread.MIN_PRIORITY); for(int i = 3; i < nameA.length; i++) st[i] .start(); System.out.println("\t\tThe Threads with low priority started"); for(int i = 0; i < 3; i++) st[i] .start(); System.out.println("\t\tAll Threads Started"); } }
|
Making Nick Making Marie Making George Making Isabelle Making Pierre Making Rose Making Salome The Threads with low priority started Isabellestart at 21:21:18:326pr -> 1 Pierrestart at 21:21:18:326pr -> 1 Rosestart at 21:21:18:326pr -> 1 Salomestart at 21:21:18:327pr -> 1 Nickstart at 21:21:18:328pr -> 10 Mariestart at 21:21:18:328pr -> 10 All Threads Started Georgestart at 21:21:18:329pr -> 10 Thread George(5) priority -> 10 Thread Isabelle(5) priority -> 1 Thread Salome(5) priority -> 1 Thread Nick(5) priority -> 10 Thread Rose(5) priority -> 1 Thread Pierre(5) priority -> 1 Thread Marie(5) priority -> 10 Thread George(4) priority -> 10 Thread Isabelle(4) priority -> 1 Thread Nick(4) priority -> 10 Thread Salome(4) priority -> 1 Thread Marie(4) priority -> 10 Thread Pierre(4) priority -> 1 Thread Rose(4) priority -> 1 Thread George(3) priority -> 10 Thread Rose(3) priority -> 1 Thread Isabelle(3) priority -> 1 Thread Pierre(3) priority -> 1 Thread Nick(3) priority -> 10 Thread Marie(3) priority -> 10 Thread Salome(3) priority -> 1 Thread Rose(2) priority -> 1 Thread George(2) priority -> 10 Thread Isabelle(2) priority -> 1 Thread Salome(2) priority -> 1 Thread Pierre(2) priority -> 1 Thread Nick(2) priority -> 10 Thread Marie(2) priority -> 10 Thread Rose(1) priority -> 1 Thread Rose end Thread George(1) priority -> 10 Thread George end Thread Isabelle(1) priority -> 1 Thread Isabelle end Thread Pierre(1) priority -> 1 Thread Pierre end Thread Salome(1) priority -> 1 Thread Salome end Thread Nick(1) priority -> 10 Thread Marie(1) priority -> 10 Thread Marie end Thread Nick end |