МІНІСТЕРСТВО ОСВІТИ ТА НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”
Звіт
Про виконання лабораторної роботи №3
На тему: «Використання потоків в Java»
Мета роботи: Метою роботи є придбання навиків роботи з потоками при програмуванні на мові Java.
.
КОРОТКІ ТЕОРЕТИЧНІ ВІДОМОСТІ
РEАЛІЗАЦІЯ ПОТОКІВ В JAVA
Мова Java є однією з небагатьох мов програмування, які містять засоби підтримки потоків. У мові Java потоки звичайно використовуються для того, щоб аплети могли виконувати якісь дії в той час, як Web-браузер продовжує свою роботу, проте потоки можна застосувати в будь-якій програмі при необхідності паралельного виконання декількох завдань.
Так, наприклад, при створенні колективом програмістів великого і складного програмного продукту, як правило, окремі модулі програми розробляються паралельно окремими програмістами або групами програмістів. В цьому випадку процес розробки кожного модуля програми можна представити як окремий потік.
Реалізація використання потоків в програмах на мові може виконуватися двома способами:
- розширенням класу Thread;
- реалізацією інтерфейсу Runnable.
При першому способі клас стає потоковим, якщо він створений як розширення класу Thread, який визначений в пакеті java.lang, наприклад:
public class GreatRace extends Thread
При цьому стають доступними всі методи потоків. Звичайно, коли необхідно, щоб даний клас є розширенням деякого іншого класу і в ньому необхідно реалізувати потоки, попередній підхід не можна використовувати, оскільки, як вже указувалося, мові Java немає множинного спадкоємства. Для вирішення цієї проблеми для даного класу потрібно реалізувати інтерфейс Runnable, наприклад:
· public class GreatRace extends Applet implements Runnable
· Інтерфейс Runnable має тільки один метод public void run(). Насправді клас Thread також реалізує цей інтерфейс, проте стандартна реалізація run() у класі Thread не виконує ніяких операцій. Необхідно або розширити клас Thread, щоб включити в нього новий метод run(), або створити об'єкт Runnnable і передати його конструктору потоку. Коли створюється клас, що реалізовує інтерфейс Runnable, цей клас повинен перевизначити метод run(). Саме цей метод виконує фактичну роботу, покладену на конкретний потік.
· Створити потік можна за допомогою одного з наступних конструкторів:
· public Thread()
· public Thread(String name)
public Thread(Runnable target)
· public Thread(Runnable target, String name)
public Thread(ThreadGroup group, String name)
· public Thread(ThreadGroup group, Runnable target)
· public Thread(ThreadGroup group, Runnable target, String name)
У першому конструкторі створюється потік, який використовує самого себе як такий інтерфейс Runnable. У решті конструкторів використовувані параметри мають наступний сенс:
name - ім'я, яке привласнюється новому потоку;
· target - визначення цільового об'єкту, який використовуватиметься новим об'єктом Thread при запуску потоків. Якщо опустити цей параметр або привласнити йому значення null, новий об'єкт Thread запускатиме потоки за допомогою виклику методу run() поточного об'єкту Thread. Якщо при створенні нового об'єкту Thread указується цільовий об'єкт, то для запуску нових процесів він викликатиме метод run() вказаного цільового об'єкту;
· group - призначений для приміщення нового об'єкту Thread в дерево об'єктів даного класу. Якщо опустити даний параметр або привласнити йому значення null, новий об'єкт класу Thread стане членом поточної групи потоків ThreadGroup.
Метод public String toString() повертає рядкове представлення потоку, включаючи ім'я потоку, пріоритет і ім'я групи, а методи public final String getName() і public final void setName(String name) дозволяють одержати ім'я потоку або встановити ім'я потоку.
· Запуск потоку виконує метод public void start() throws IllegalThreadStateException (виключення кидається, якщо робиться спроба запуску вже запущеного потоку).
· Для зупинки потоку рекомендується потоку, що зупиняється, привласнити значення null, наприклад:
· Thread myThread;
· myThread.start(); // Запуск потоку
· myThread = null; // Зупинка або завершення потоку
· Припустимо, що на якомусь етапі роботи над програмним проектом необхідні два модулі, над якими працюють дві групи програмістів. Етап може початися, тільки якщо обидві групи закінчили роботу над своїми модулями, тобто однієї з груп програмістів доведеться чекати закінчення роботи над модулем іншої групи. Для такого узгодження дій використовується public final void join() throws InterruptedException.
· Методу join можна також передати значення тайм-ауту, використовуючи його варіанти public final syncronized void join(long millis) throws InterruptedException і public final syncronized void join(long millis, int nanos) throws InterruptedException. Ці методи чекають протягом millis мілісекунд або millis мілісекунд плюс nanos наносекунд.
· Якщо потрібний, щоб перед продовженням роботи потік чекав певний час, можна використовувати метод public static void sleep(long millis) throws InterruptedException або public static void sleep(long millis, int nanos) throws InterruptedException, де параметри millis і nanos мають той же сенс, що і для методу join. Метод sleep() дуже часто використовується в циклах, що управляють анімацією.
· Якщо в програмі є потік, який захоплює процесор, проводячи велику кількість обчислень, може з'явитися необхідність примушувати його час від часу "відпускати" процесор, даючи можливість виконуватися іншим потокам. Це досягається за допомогою методу public static void yield().
· Метод public void destroy() знищує потік без жодного очищення даних, що відносяться до нього, а метод public final boolean isAlive() дозволяє визначити, чи запущений потік і ще живий.
· Потоки в Java можуть переривати один одного.
Індивідуальне завдання
Програма моделює обслуговування двох потоків процесів з різними параметрами одним центральним процесором комп'ютера. Для кожного потоку задається своя черга. Черга для першого потоку має фіксований розмір, і, якщо процес згенерував в той момент, коли перша черга заповнена, процес знищується. Розмір черги для другого потоку необмежений. На кожних n запитів з першої черги (n задається як початкове дане), процесор бере на обробку один запит з другої черги. Визначити відсоток знищених процесів першого потоку і максимальну довжину другої черги.
Лістинг програми:
public class Stream {
public static void main(String[] args) {
CPU cpu =new CPU(100);
}
}
import java.text.SimpleDateFormat;
import java.util.Date;
public class CPU {
int time ;
public CPU(int time) {
this.time = time;
int n = 4;
CPUQueue tr1 = new CPUQueue(5);
CPUProcess Process1 = new CPUProcess("FirstProcess",100)
Process1.turned = tr1;
Process1.start();
CPUQueue tr2 = new CPUQueue(214);
CPUProcess Process2 = new CPUProcess("SecondProcess",100);
Process2.turned =tr2;
Process2.start();
for(int i=1;i<6;i++){
int t = getTime();
while (getTime()<(t+(time*n))){
System.out.println(Process1.turned.remove());
try{
Thread.sleep(time);
}catch(InterruptedException e){
System.out.println("Головний потік перервано");
}
}
System.out.println(Process2.turned.remove());
try{
Thread.sleep(time);
}catch(InterruptedException e){
System.out.println("Головний потік перервано");
}
}
Process1.stop();
Process2.stop();
int t=tr1.ValueTime,d = tr1.ValueDlatedTime;
System.out.println("Відсоток втрачених процесів = "+(int)(((float) d/t)*100)+"%");
System.out.println("Максимальна заповненість черги = "+tr2.max);
}
public static int getTime(){
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("mmssSSS");
String str = sdf.format(date);
int time=0;
for (int i=str.length()-1,a=0;i>=0;i--,a++){
time += ((str.charAt(i)-48)* Math.pow(10,a));
}
return time;
}
}
import java.util.Random;
public class CPUProcess implements Runnable {
String name;
Thread t;
boolean Flag = true;
CPUQueue turned ;
Random r = new Random();
int time =0;
CPUProcess(String processname,int time){
this.time = time;
name = processname;
t = new Thread(this,name);
System.out.println("Новий процес: "+ name);
}
public void run(){
while (Flag){
try{
turned.add(name+" "+r.nextInt(100));
//System.out.println(name +" "+ r);
Thread.sleep(time);
}catch (InterruptedException e){
System.out.println("Процес "+name+" перерваний.");
}
}
System.out.println("Процес "+name+" зупинений.");
}
public void start() {
t.start();
}
public void stop() {
Flag = false;
}
}
public class CPUQueue {
public CPUQueue(int max) {
Max_Langth = max;
turn = new String[Max_Langth];
}
int Max_Langth;
int max = 0;
String[] turn;
int Pointer=0;
int ValueTime =0, ValueDlatedTime =0;
void MaxLangth(int max){
Max_Langth = max;
}
boolean add (String str){
ValueTime++;
if (Pointer>=Max_Langth-1){
ValueDlatedTime++;
return false;
}else{
turn[Pointer]= str;
Pointer++;
if (Pointer>max){
max = Pointer;
}
return true;
}
}
String remove (){
for (int i=0;i<turn.length-1;i++){
}
String s = turn[0];
if (turn[0]!=null){
for (int i=0; i<turn.length-2;i++){
turn[i] = turn[i+1];
}
turn[turn.length-2] = null;
Pointer--;
}else Pointer=0;
for (int i=0;i<turn.length-1;i++){
}
return s;
}
}
Результати виконання програми:
Новий процес: FirstProcess
Новий процес: SecondProcess
FirstProcess 80
FirstProcess 51
FirstProcess 18
SecondProcess 32
FirstProcess 26
FirstProcess 49
FirstProcess 93
FirstProcess 74
SecondProcess 91
FirstProcess 77
FirstProcess 55
FirstProcess 0
FirstProcess 86
SecondProcess 42
FirstProcess 10
FirstProcess 61
FirstProcess 96
FirstProcess 97
SecondProcess 33
FirstProcess 62
FirstProcess 27
FirstProcess 63
FirstProcess 24
SecondProcess 29
Відсоток втрачених процесів = 8%
Максимальна заповненість черги = 20
Процес FirstProcess зупинений.
Процес SecondProcess зупинений.
Висновок: На цій лабораторній роботі я розвинув навиків роботи з потоками при програмуванні на мові Java.