Семинар #6 - Факультета информационных технологий НГУ

реклама
Факультет Информационных Технологий, 2-й курс, II семестр
Курс: Объектно-ориентированное программирование
Семинар №6. Синхронизация. Многопоточность.
План
1. Вопросы по заданиям семинара №5
2. Механизм синхронизации в Java. Нити выполнения, объекты и мониторы.
3. Захват и освобождение монитора, блок synchronized
4. Класс потока Thread, запуск нового потока
5. Метод выполнения run(), время жизни потока
6. Пользовательский и Daemon потоки
7. Ожидание и прерывание потока. Методы join и interrupt
8. Исключение InterruptedException
9. Текущий поток выполнения Thread.currentThread()
10. Остановка выполнения без захвата монитора в методе Thread.sleep()
11. Захват и временное освобождение монитора. Методы wait и notify класса Object
12. Блокирование потока DeadLock. Методы stop, suspend, resume и destroy
13. Интерфейс Runnable в качестве альтернативы наследования класса Thread
Пример запуска потока
public class RunThread {
public static void main(String[] args) {
System.out.println("Start");
Thread t = new Thread("Test-Thread") {
public void run() {
System.out.println("Run and sleep " + getName());
try {
sleep(3000);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
};
t.start();
try {
t.join();
} catch (InterruptedException e) {
}
System.out.println("Finish");
}
}
Пример не синхронизированного доступа
public class Increment extends Thread {
private static int NUM_THREADS = 3;
private static int NUM_INCREASES = 1000000;
private static long data;
//private static Object obj = new Object();
public Increment(String name) {
super(name);
}
public void run() {
System.out.println("Thread "+Thread.currentThread().getName()+"
started");
1
Факультет Информационных Технологий, 2-й курс, II семестр
Курс: Объектно-ориентированное программирование
for (int i=0; i<NUM_INCREASES; i++) {
//synchronized (obj) {
data++;
//}
}
System.out.println("Thread "+Thread.currentThread().getName()+"
stopped");
}
public static void main(String[] args) {
Increment threads[] = new Increment[NUM_THREADS];
for(int i=0; i<NUM_THREADS; i++) {
threads[i] = new Increment("#"+i);
threads[i].start();
}
for(int i=0; i<NUM_THREADS; i++) {
try {
threads[i].join();
} catch (InterruptedException e) {}
}
System.out.println("Expected: "+(NUM_THREADS*NUM_INCREASES)+" but
it is: "+data);
}
}
Примеры синхронизированного доступа
public static synchronized void syncIncMethod() {
data++;
}
public static void syncIncBlock() {
synchronized(Increment.class) {
data++;
}
}
Захват монитора объекта
synchronized (obj) { // захват монитора объекта obj
try {
obj.wait(); // поток освобождает монитор и застывает в этой точке
// эта сторока выполнится только после того, как другой поток
скажет obj.notify()
} catch (InterruptedException e) {
// если поток разбудили через метод interrupt();
}
}
synchronized (obj) { // захват монитора объекта obj
obj.notify(); // посылка сообщения потоку, который первый вызвал
obj.wait() и все еще ждет
}
synchronized (obj) { // захват монитора объекта obj
obj.notifyAll(); // посылка сообщения всем потокам, которые висят в
obj.wait()
2
Факультет Информационных Технологий, 2-й курс, II семестр
Курс: Объектно-ориентированное программирование
}
Пример deadlock
public class Deadlock {
private Run1 run1;
private Run2 run2;
public class Run1 implements Runnable {
public void run() {
f1();
}
public synchronized void f1() {
try {
Thread.sleep(1000);
} catch (InterruptedException e){
return;
}
System.out.println("Run1.f1()");
run2.f2();
}
public synchronized void f2() {
System.out.println("Run1.f2()");
}
}
public class Run2 implements Runnable {
public void run() {
f1();
}
public synchronized void f1() {
try {
Thread.sleep(1000);
} catch (InterruptedException e){
return;
}
System.out.println("Run2.f1()");
run1.f2();
}
public synchronized void f2() {
System.out.println("Run2.f2()");
}
}
private void init() {
run1 = new Run1();
new Thread(run1).start();
run2 = new Run2();
new Thread(run2).start();
}
public static void main(String args[]) {
new Deadlock().init();
}
}
3
Факультет Информационных Технологий, 2-й курс, II семестр
Курс: Объектно-ориентированное программирование
Задание 6-1: Секундомер
Написать секундомер - класс Stopwatch - для замера времени в отдельном потоке
выполнения. В классе должны быть реализованы следующие методы
 start – начинает отчет времени
 stop – прерывает отчет времени
 reset – сбрасывает текущее значение секундомера
 getTime – возвращает отсчитанное время в миллисекундах
Для демонстрации работы секундомера написать консольное приложение. Пользователю
должны быть доступными следующие команды:
 start N – запустить секундомер и дать ему идентификатор N
 stop N – остановить секундомер с идентификатором N
 reset N – сбросить время у секундомера с идентификатором N
 time N – показать время у секундомера с идентификатором N
 help – список команд
 exit – выход
Если не указан идентификатор, то используется 0 как идентификатор по умолчанию.
Хранить секундомеры лучше в Map<String, Stopwatch>.
Задание 6-2: Подсчет простых чисел
Написать Swing-приложение для подсчета простых чисел в параллельных потоках.
Каждый поток подсчитывает простые числа из заданного диапазона. Всего должно быть
запущено три потока подсчета. Полученные числа выдаются на экран. Можно
запускать/останавливать подсчет несколько раз.
Пользователю доступны следующие элементы управления:
1. Кнопка запуска всех потоков
2. Кнопка остановки всех потоков
3. Поле (JTextArea) для вывода результата в виде:
<номер потока>: <число>
Например:
1: 11
2: 23
2: 31
1: 17
4. 4 поля ввода диапазонов чисел для подсчета. Получается 3 диапазона (между 4-мя
числами) для каждого потока.
5. Три строки с информацией о состоянии каждого потока
4
Скачать