Студопедия
Главная страница | Контакты | Случайная страница

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Практическое занятие № 7

Читайте также:
  1. Анализ бизнес среды: практическое использование моделей STEP/PEST, SLEPT
  2. ВЫШИВАНИЕ – ДОМАШНЕЕ ЗАНЯТИЕ, РЕМЕСЛО И ПРОМЫСЕЛ
  3. Глава 6. Первое занятие
  4. Гоулд С.Э., Рубин Р. Бизнес в стиле дзен: Практическое руководство для дзен - предпринимателя / Пер. – 2 – е изд. М.: Добрая книга, 2006. – 207 с. 3000 экз.
  5. Занятие 1
  6. Занятие 1. Манера речи Синдарин.
  7. Занятие 10-е. Тема: "Умение хоронить свои потери".
  8. Занятие 10. Одноатомные спирты. Тест по теме «Одноатомные спирты». Задачи и упражнения на одноатомные спирты.
  9. ЗАНЯТИЕ 11
  10. Занятие 12-е. Тема: "Я имею право".

 

Тема: «Потоки исполнения в приложениях Java».

 

Потоки исполнения (thread) представляют собой составляющую программного исполнения, которая работает независимо от других потоков. Java-программы могут состоять из множества независимых потоков, исполняемых как будто на независимых процессорах, реализуемых на основных пакетах:

· интерфейс java.lang.Runnable определяет метод run(), функционирующий подобно блоку кода, исполняемого потоком;

· можно использовать оператор и модификатор synchronized для написания блоков кода и целых методов, требующих блокирования доступа к ним других потоков. Механизм гарантирует, что два потока не смогут одновременно исполнять блок с общими данными;

· для приостановки и возобновления потоков могут использоваться методы wait() и notify() пакета java.lang.Object.

 

Пример: Демонстрирует возможности определения и запуска потоков, манипуляции ими, установки приоритетов между ними.

 

public class ThreadDemo extends Thread {

/**

* Метод замещает метод run() класса Thread. Он предоставляет

* тело для этого процесса.

**/

public void run() { for(int i = 0; i < 5; i++) compute(); }

 

/**

* Метод main создает и запускает дополнительно к начальному потоку

* еще два потока для вызова метода main().

**/

public static void main(String[] args) {

// Создание первого потока

// его телом является метод run()

ThreadDemo thread1 = new ThreadDemo();

 

// создание второго потока исполнения объекта Runnable

// конструктором Thread(). Телом потока является метод run()

// объекта Runnable.

Thread thread2 = new Thread(new Runnable() {

public void run() { for(int i = 0; i < 5; i++) compute(); }

});

 

// Установка приоритетов потоков

if (args.length >= 1) thread1.setPriority(Integer.parseInt(args[0]));

if (args.length >= 2) thread2.setPriority(Integer.parseInt(args[1]));

 

// Запуск двух потоков на исполнение

thread1.start();

thread2.start();

 

// Метод main() запущен начальным потоком исполнения

for(int i = 0; i < 5; i++) compute();

 

// Завершение потоков

// try {

// thread1.join();

// thread2.join();

// } catch (InterruptedException e) {}

 

// Java VM завершит работу после метода main()

}

 

// Объекты ThreadLocal представляют значение, доступ к которым

// осуществляют методы get() и set().

// Объект отслеживает число вызовов метода compute() каждым потоком.

static ThreadLocal numcalls = new ThreadLocal();

 

/** Подсчет количества вызовов потоком */

static synchronized void compute() {

// отобразить имя потока и количество вызовов

Integer n = (Integer) numcalls.get();

if (n == null) n = new Integer(1);

else n = new Integer(n.intValue() + 1);

numcalls.set(n);

 

// имя потока и количество вызовов

System.out.println(Thread.currentThread().getName() + ": " + n);

 

// имитация нагрузки на процессор потока исполнения

for(int i = 0, j=0; i < 1000000; i++) j += i;

 

// сортировка задержек ввода/вывода

try {

// приостановка исполнения

Thread.sleep((int)(Math.random()*100+1));

}

catch (InterruptedException e) {}

 

// Потоки исполняются без конфликтов между собой.

Thread.yield();

}

}

 

Каждый поток исполнения в Java принадлежит какой-либо группе потоков исполнения ThreadGroup, методами которой можно осуществлять управление поведением потоков. Т.е. образуется иерархия групп потоков исполнения.

Пример: Использует класс ThreadLister, содержащий метод listAllThreads(), который отображает эту иерархию, выводя список исполняемых потоков, их приоритетов и групп.

 

import java.io.*;

import java.awt.*; // AWT классы для демонстрации программы

import javax.swing.*; // Swing GUI для создания интерфейса программы

 

/**

* Класс содержит метод для вывода потоков исполнения

**/

public class ThreadLister {

/** Отображение информации о потоке. */

private static void printThreadInfo(PrintWriter out, Thread t,

String indent) {

if (t == null) return;

out.println(indent + "Thread: " + t.getName() +

" Priority: " + t.getPriority() +

(t.isDaemon()?" Daemon":"") +

(t.isAlive()?"":" Not Alive"));

}

 

/** Отображение информации о группе потоков */

private static void printGroupInfo(PrintWriter out, ThreadGroup g,

String indent) {

if (g == null) return;

int num_threads = g.activeCount();

int num_groups = g.activeGroupCount();

Thread[] threads = new Thread[num_threads];

ThreadGroup[] groups = new ThreadGroup[num_groups];

 

g.enumerate(threads, false);

g.enumerate(groups, false);

 

out.println(indent + "группа потоков: " + g.getName() +

" наивысший приоритет: " + g.getMaxPriority() +

(g.isDaemon()?" демон":""));

 

for(int i = 0; i < num_threads; i++)

printThreadInfo(out, threads[i], indent + " ");

for(int i = 0; i < num_groups; i++)

printGroupInfo(out, groups[i], indent + " ");

}

 

/** находим корневую группу и рекурсивный вывод содержимого */

public static void listAllThreads(PrintWriter out) {

ThreadGroup current_thread_group;

ThreadGroup root_thread_group;

ThreadGroup parent;

 

// получение группы текущего потока исполнения

current_thread_group = Thread.currentThread().getThreadGroup();

 

// поиск корневой группы

root_thread_group = current_thread_group;

parent = root_thread_group.getParent();

while(parent!= null) {

root_thread_group = parent;

parent = parent.getParent();

}

 

// ее вывод

printGroupInfo(out, root_thread_group, "");

}

 

/**

* Метод main() создает интерфейс пользователя для вывода информации

**/

public static void main(String[] args) {

// Интерфейс Swing GUI

JFrame frame = new JFrame("ThreadLister Demo");

JTextArea textarea = new JTextArea();

frame.getContentPane().add(new JScrollPane(textarea),

BorderLayout.CENTER);

frame.setSize(500, 400);

frame.setVisible(true);

 

// Формирование строки threadlisting

StringWriter sout = new StringWriter(); // для приема

PrintWriter out = new PrintWriter(sout);

ThreadLister.listAllThreads(out); // вывод списка потоков

out.close();

String threadListing = sout.toString(); // вывод строки

 

// отображение в интерфейсе GUI

textarea.setText(threadListing);

}

}

 

Для гарантированного использования только одного потока исполнения в программном приложении используется синхронизация, связанная с наложением исключительной блокировки (exclusive lock). При «взаимной блокировке» (beadlock), когда несколько потоков ожидают ресурс данных, все потоки останавливаются и программа завершается.

Пример: Создает ситуацию взаимной блокировки, в которой два потока пытаются захватить два ресурса.

 

public class Deadlock {

public static void main(String[] args) {

// Это два ресурса, за которые потоки будут бороться

final Object resource1 = "resource1";

final Object resource2 = "resource2";

// первый поток пытается захватить resource1, затем resource2

Thread t1 = new Thread() {

public void run() {

// захват resource1

synchronized(resource1) {

System.out.println("поток 1: захват resource 1");

 

// пауза ввода/вывода для запуска второго потока

try { Thread.sleep(50); }

catch (InterruptedException e) {}

 

// ожидание захвата resource 2

synchronized(resource2) {

System.out.println("поток 1: захвачен resource 2");

}

}

}

};

 

// второй поток исполнения. Он захватывает resource2, затем resource1

Thread t2 = new Thread() {

public void run() {

// поток захватывает resource 2

synchronized(resource2) {

System.out.println("поток 2: захвачен resource 2");

 

// пауза.

try { Thread.sleep(50); }

catch (InterruptedException e) {}

 

// попытка захватить resource1.

// 1 поток захватил resource1 и держит его,

// пока не захватит resource2. Программа зависает

synchronized(resource1) {

System.out.println("поток 2: захвачен resource 1");

}

}

}

};

 

// запуск двух потоков. Возникает взаимная блокировки и

// программа зависает.

t1.start();

t2.start();

}

}

 

Пример: С помощью класса java.util.Timer и java.util.TimerTask можно организовать временную последовательность вызова метода run() и организовать управление потоками.

 

public abstract class TimerTask implements Runnable {

boolean cancelled = false; // Была ли отмена?

long nextTime = -1; // Момент назначения следующего исполнения?

long period; // интервал исполнения

boolean fixedRate; // запуск исполнения с фиксированной частотой?

 

protected TimerTask() {}

 

/**

* Прекращение исполнения задачи (true)

* и false, если потока не было.

**/

public boolean cancel() {

if (cancelled) return false; // уже отменена;

cancelled = true; // отмена

if (nextTime == -1) return false; // не исполнялась;

return true;

}

 

/**

* момент назначения исполнения методом run()

**/

public long scheduledExecutionTime() { return nextTime; }

 

/**

* подклассы замещают метод, задавая код исполнения.

* класс Timer вызывает его из внутреннего потока исполнения.

**/

public abstract void run();

 

// класс Timer передает классу Task сведения о расписании.

void schedule(long nextTime, long period, boolean fixedRate) {

this.nextTime = nextTime;

this.period = period;

this.fixedRate = fixedRate;

}

 

// метод, вызываемый классом Timer после вызова метода run.

boolean reschedule() {

if (period == 0 || cancelled) return false; // не запускать

if (fixedRate) nextTime += period;

else nextTime = System.currentTimeMillis() + period;

return true;

}

}

 

Пример: Демонстрируются задачи, за исполнение которых отвечает Timer.

 

import java.util.Date;

import java.util.TreeSet;

import java.util.Comparator;

 

 

public class Timer {

// Задачи, за исполнение которых отвечает Timer.

TreeSet tasks = new TreeSet(new TimerTaskComparator());

 

// организация потока исполнения

TimerThread timer;

 

/** конструктор, создающий класс Timer, не использующий поток-демон */

public Timer() { this(false); }

 

/** главный конструктор */

public Timer(boolean isDaemon) {

timer = new TimerThread(isDaemon); // TimerThread определяется ниже

timer.start(); // запуск потока исполнения

}

 

/** остановка потока timer и завершение задач */

public void cancel() {

synchronized(tasks) { // один поток в момент времени!

timer.pleaseStop(); // флаг на остановку потока

tasks.clear(); // снятие задач

tasks.notify(); // вывод потока из ожидания wait().

}

}

 

/** однократное исполнение задачи с задержкой */

public void schedule(TimerTask task, long delay) {

task.schedule(System.currentTimeMillis() + delay, 0, false);

schedule(task);

}

 

/** включение в расписание задачи на данный момент времени */

public void schedule(TimerTask task, Date time) {

task.schedule(time.getTime(), 0, false);

schedule(task);

}

 

/** запуск периодического исполнения задачи в заданное время */

public void schedule(TimerTask task, Date firstTime, long period) {

task.schedule(firstTime.getTime(), period, false);

schedule(task);

}

 

/** старт после задержки */

public void schedule(TimerTask task, long delay, long period) {

task.schedule(System.currentTimeMillis() + delay, period, false);

schedule(task);

}

 

/**

* организация периодического запуска с фиксированной частотой.

**/

public void scheduleAtFixedRate(TimerTask task, long delay, long period) {

task.schedule(System.currentTimeMillis() + delay, period, true);

schedule(task);

}

 

/** расписание исполнения после заданного времени */

public void scheduleAtFixedRate(TimerTask task, Date firstTime,

long period)

{

task.schedule(firstTime.getTime(), period, true);

schedule(task);

}

 

 

// внутренний метод добавляет задачу

void schedule(TimerTask task) {

synchronized(tasks) { // один поток в момент времени!

tasks.add(task); // добавка задачи

tasks.notify(); // возобновление потоков

}

}

 

/**

* внутренний класс для упорядочения задач.

**/

static class TimerTaskComparator implements Comparator {

public int compare(Object a, Object b) {

TimerTask t1 = (TimerTask) a;

TimerTask t2 = (TimerTask) b;

long diff = t1.nextTime - t2.nextTime;

if (diff < 0) return -1;

else if (diff > 0) return 1;

else return 0;

}

public boolean equals(Object o) { return this == o; }

}

 

/**

* внутренний класс, определяющий поток исполнения

* scheduled times

**/

class TimerThread extends Thread {

// управление остановкой потока.

volatile boolean stopped = false;

 

// конструктор

public TimerThread(boolean isDaemon) { setDaemon(isDaemon); }

 

// остановка потока

public void pleaseStop() { stopped = true; }

 

// тело потока

public void run() {

TimerTask readyToRun = null; // задача?

 

// организация цикла до остановки потока.

while(!stopped) {

// существование задачи!

if (readyToRun!= null) {

if (readyToRun.cancelled) { // если отмена.

readyToRun = null;

continue;

}

// запуск задачи.

readyToRun.run();

// изменение расписания задачи

if (readyToRun.reschedule())

schedule(readyToRun);

// запуск

readyToRun = null;

// возврат к началу цикла

continue;

}

 

// блокировка на набор задач

synchronized(tasks) {

long timeout; // время задержки?

 

if (tasks.isEmpty()) { // ожидание следующей задачи

timeout = 0; // следующая задача

}

else {

// выбор первой задачи

TimerTask t = (TimerTask) tasks.first();

// следующий запуск?

timeout = t.nextTime - System.currentTimeMillis();

// пора запускать

if (timeout <= 0) {

readyToRun = t; // сохранение

tasks.remove(t); // удаление из набора

// выход из синхронизованного раздела

// пока не запущена задача

continue;

}

}

 

// Ожидание команды notify() для следующего запуска

try { tasks.wait(timeout); }

catch (InterruptedException e) {}

 

// возвращение к началу цикла while

}

}

}

}

 

/** внутренний класс тестовой программы */

public static class Test {

public static void main(String[] args) {

final TimerTask t1 = new TimerTask() { // задача 1: печать "boom!"

public void run() { System.out.println("boom!"); }

};

final TimerTask t2 = new TimerTask() { // задача 2: печать "BOOM?"

public void run() { System.out.println("\tBOOM?"); }

};

final TimerTask t3 = new TimerTask() { // задача 3: отмена задач

public void run() { t1.cancel(); t2.cancel(); }

};

 

// создание объекта timer, и включение нескольких задач

final Timer timer = new Timer();

timer.schedule(t1, 0, 500); // boom каждые 0.5c

timer.schedule(t2, 2000, 2000); // BOOM каждые 2с

timer.schedule(t3, 5000); // остановить через 5c

 

// последняя задача: начав через 5c, провести обратный отсчет

// от 5, уничтожить timer, завершить программу

timer.scheduleAtFixedRate(new TimerTask() {

public int times = 5;

public void run() {

System.out.println(times--);

if (times == 0) timer.cancel();

}

},

5000,500);

}

}

}

 

 




Дата добавления: 2015-09-11; просмотров: 81 | Поможем написать вашу работу | Нарушение авторских прав

ВВЕДЕНИЕ | Глава 1.1. Особенности разработки программы на языке Java | Практическое занятие № 1 | Практическое занятие № 2 | Практическое занятие № 3 | Практическое занятие № 4 | Практическое занятие № 5 | Пример 2.2. | Глава 2.2. Графические интерфейсы пользователя в Java | Компоненты. |


lektsii.net - Лекции.Нет - 2014-2025 год. (0.048 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав