Основы программирования на языке Java

advertisement
Основы программирования на
языке Java
Стандартная библиотека Java:
java.net;
Многопоточное программирование
(С) Всеволод Рылов, все права защищены
Новосибирск, 2004
1
Ключевые слова – статус
Ключевые слова, которые уже известны на текущий момент:
abstractdefault
do
double
else
extends
if
implements
import
instanceof
int
private
protected
public
return
short
this boolean
throw break
throws byte
transient case
try
catch
char
class
final
finally
float
interface
long
native
static
strictfp
super
void
volatile
while
const
goto
for
package
new
synchronized
switch
continue
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
2
Сетевое взаимодействие – стек протоколов

Сетевая модель DoD (Internet):
Стек протоколов
Программы
HTTP FTP
Уровень приложений (URL)
TCP, UDP
Транспортный уровень (порт)
IP
Ethernet
Новосибирск, 2004
Сетевой уровень (ip адрес)
Физический уровень
(С) Всеволод Рылов, все права защищены
3
Взаимодействие в Internet
FTP client
HTTP / TCP & UDP
Client PC
IP
IP
FTP Server
Internet
www.yandex.ru
Client PC
WWW
browser
193.124.219.107 : 12345
Новосибирск, 2004
DNS
HTTP / TCP
213.180.216.200
WWW Server
213.180.216.200 : 80
(С) Всеволод Рылов, все права защищены
4
Работа с сетью

Для работы с сетью используется пакет java.net, предоставляющий
средства:
 адресации в Internet (InetAddress, + средства java 1.4:
Inet4Address, Inet6Address, InetSocketAddress, SocketAddress)
 работы с протоколом TCP (Socket, ServerSocket, SocketOptions)
 работы с протоколом UDP (DatagramSocket, DatagramPacket,
MulticastSocket)
 работы с URL и поддержки HTTP (URL, URLConnection,
HttpURLConnection, JarURLConnection, URLDecoder,
URLEncoder, ContentHandler, URLStreamHandler)
 авторизации в Internet (Authenticator, PasswordAuthentication)
 динамической загрузки классов из сети (URLClassLoader)
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
5
Исключения пакета java.net
IOException
(from io)
UnknownServiceException
UnknownHostException
SocketException
ProtocolException
MalformedURLException
NoRouteToHostException
ConnectException
BindException
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
6
Параллельный TCP сервер
import java.net.*;
import java.io.*;
public class TCPServer {
public static void main(String[] args) throws IOException {
//Создаем новый серверный Socket на порту 2048
ServerSocket s = new ServerSocket(2048);
while (true)
{
Socket clientSocket = s.accept(); //принимаем соединение
System.out.println("Получено соединение от:"+clientSocket.getInetAddress()
+":"+clientSocket.getPort());
//Создаем и запускаем поток для обработки запроса
Thread t = new Thread(new RequestProcessor(clientSocket));
System.out.println("Запуск обработчика...");
t.start();
}
}
}
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
7
Параллельный TCP сервер - продолжение
class RequestProcessor implements Runnable
{
Socket s; //Точка установленного соединения
RequestProcessor(Socket s) {
this.s = s;
}
public void run() {
try {
InputStream input = s.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
OutputStream output = s.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(output);
String line = "";
while ( true ) {
System.out.println("Ожидаем строку...");
line = reader.readLine();
if (line == null) break;
System.out.println("Получена строка:"+line);
writer.write("ответ от:"+s.getLocalAddress()+":"+s.getLocalPort()
+" для:"+s.getInetAddress()+":"+s.getPort()+" : "+line+"\n");
writer.flush();
}
writer.close();
System.out.println("Обработчик завершил работу");
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
8
TCP Клиент для сервера
import java.io.*;
import java.net.*;
public class TCPClient {
public static void main(String[] args) throws IOException {
Socket s = new Socket("127.0.0.1",2048);
OutputStreamWriter writer = new OutputStreamWriter(s.getOutputStream());
BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = "";
do {
System.out.print("Введите строку:");
line = consoleReader.readLine();
if (line.equalsIgnoreCase("exit")) break;
writer.write(line+"\n");
writer.flush();
line = reader.readLine();
System.out.println("Получен ответ:" + line);
} while (true);
writer.close();
}
}
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
9
Многопоточное программирование





Системы с одним потоком используют подход, называемый циклом
обработки событий с буферизацией (event loop with pooling)
 Единовременно может обрабатываться только одно событие
 При блокировке потока прекращается работа всей программы
В системах с многими потоками главный цикл и механизм
буферизации не нужен:
 Единовременно возможна обработка нескольких событий
 Блокировка одного потока не влияет на работу других потоков
Поток может находится в нескольких состояниях: running, ready to
run, suspended, resumed, blocked, stopped, terminated
Переключение потоков (context switch) происходит на основе
динамически изменяющихся приоритетов (preemptive multitasking)
либо на добровольной основе
Для синхронизации потоков используются мониторы
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
10
Классы для реализации многопоточности
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
11
Создание потоков


реализация интерфейса Runnable
порождение от класса Thread
class MyRunnable implements Runnable
{
public void run() {
//execution starts here
}
}
…
Runnable target = new MyRunnable();
Thread t = new Thread (target, “one”);
t.start();
class MyThread extends Thread
{
public void run() {
//execution starts here
}
}
…
MyThread t = new MyThread();
t.setName(“two”);
t.start();
Для получения текущего потока нужно воспользоваться
Thread.currentThread()
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
12
Мониторы и синхронизация потоков



С каждым объектом ассоциирован монитор, который можно
использовать для синхронизации доступа к объекту
В один момент времени только один поток может обладать
монитором объекта
Монитор объекта захватывается с помощью вызова синхронного
метода либо в синхронном блоке:
class MyClass {
public synchronized void doIt() {
…
}
}
…
MyClass obj = new MyClass();
obj.doIt(); //Захват монитора obj
Новосибирск, 2004
class AnotherClass {
public void doIt() {…}
}
…
AnotherClass obj = new AnotherClass();
//Захват монитора obj
synchronized (obj) {
obj.doIt();
}
(С) Всеволод Рылов, все права защищены
13
Освобождение монитора






Монитор объекта освобождается автоматически по завершению
выполнения синхронизированного метода или блока
Монитор может быть освобожден добровольно с помощью вызова
на объекте методов wait(), wait(…). При этом вызвавший метод
поток блокируется.
Для того чтобы воспользоваться семейством методов wait нужно
захватить монитор объекта
Методы notify() и notifyAll() позволяют возобновить исполнение
потока(ов) заблокированного(ых) на мониторе объекта с помощью
вызова метода из семейства wait()
Для того чтобы вызвать notify или notifyAll нужно захватить
монитор объекта
Вызов метода notify() приведет к пробуждению первого
попавшегося блокированного на объекте потока по завершению
синхронизированного метода или блока в котором вызван notify()
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
14
Пример синхронизации потоков
class Store {
class Consumer extends Thread {
Store s;
int count;
Consumer (Store s) {super();this.s=s;}
public synchronized void put() {
public void run() {
count++;
s.get();
notify();
}
}
}
class Producer extends Thread {
public synchronized void get() {
Store s;
while (true)
Producer (Store s) {super();this.s=s;}
if (count > 0) {
public void run() {
count--; return;
s.put();
}
}
public static void main(…) {
else
Store s = new Store();
try {
Consumer c = new Consumer(s);
wait();
Producer p = new Producer(s);
} catch (InterruptedException e){…}
c.start(); p.start();
}
}
}
}
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
15
Поток 1 : Thread
Обект
Поток
запущ ен
вызван synchronzied метод
Поток 2 : Thread
Поток
запущ ен
Захвачен монитор
объекта
вызван wait
вызван synchronized метод
Ожидание
монитора объекта
Монитор объекта
освобожден
Поток ожидает
пробуждения
Захвачен монитор
объекта
notify
Вызван метод
notify
выход из synchronized метода
Ожидание
монитора объекта
Монитор объекта
освобожден
Действие
завершено
Захвачен монитор
объекта
выход из synchronized метода
Монитор объекта
освобожден
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
16
Взаимная блокировка (deadlock)





Поток T1 захватывает монитор объекта X
Поток T2 захватывает монитор объекта Y
Поток T1 пытается вызвать синхронизированный метод объекта Y и,
таким образом, блокируется
Поток T2 пытается вызвать синхронизированный метод объекта X и
также блокируется
T1 и T2 оказываются в состоянии deadlock
В сложном случае в состояние взаимной блокировки могут оказаться
несколько потоков на нескольких мониторах объектов. Такую
ситуацию очень сложно отлаживать
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
17
Управление потоками
Для управления потоком служат следующие методы класса
java.lang.Thread:
 start() – запускает поток на исполнение
 interrupt() – прерывает исполнение потока. Поток может перехватить
исключение InterruptedException
 pause() – приостанавливает исполнение потока (deprecated). Поток
не освобождает захваченные мониторы
 resume() – возобновляет исполнение потока (deprecated)
 stop() – останавливает поток (deprecated). Поток освобождает
захваченные мониторы
 destroy() – разрушает поток (not implemented)
 sleep() – приостанавливает исполнение потока на определенное
время
 join() – ожидает завершения потока
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
18
Почему pause() и resume() небезопасны


Если поток T1 приостановлен с помощью pause() в момент, когда он
захватил монитор объекта X, то монитор объекта остается
захваченным. Если окажется что другому потоку T2, который должен
возобновить работу T1 с помощью resume(), также понадобится
монитор объекта X, то потоки окажутся во взаимной блокировке.
Поэтому pause() и resume() объявлены deprecated и не должны
использоваться. Вместо вызова pause() и resume() можно заставить
поток, которым нужно управлять, проверять значение какой ни будь
переменной в которую можно заносить значение соответствующее
желаемому состоянию потока. Синхронизацию можно обеспечить с
помощью монитора объекта и вызовов wait(), notify().
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
19
Почему небезопасен метод stop()




Вызов метода stop() заставляет поток освободить захваченные
мониторы
Если с помощью мониторов был защищен какой-ни будь ресурс
(объект), то на момент вызова stop этот ресурс (объект) может
оказаться в не консистентном состоянии
При этом другие потоки могут получить доступ к этому ресурсу что
скорее всего приведет к некорректной работе программы. Поэтому
метод stop() объявлен deprecated
Вместо использования stop() можно, как и в случае с методами
pause() и resume(), воспользоваться специальной переменной,
которая должна хранить желаемое состояние потока. Поток должен
проверять значение этой переменной и принимать решение о
дальнейшей работе на основании этого значения.
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
20
Пул потоков (thread pool)




Поток является относительно дорогим ресурсом и его создание
может быть сопряжено со значительными накладными расходами
При разработке программ – серверов зачастую возникает
необходимость в параллельной обработке задач или запросов, при
этом создание потока каждый раз, когда это нужно оказывается
неэффективной стратегией.
Для решения подобной проблемы можно воспользоваться «пулом
потоков». Пул потоков содержит несколько потоков готовых к работе,
которых можно использовать по мере необходимости
Пул потоков должен обеспечивать:
 возможность быстрого выделения потока для работы
 возможность высвобождения потока
 систему оповещения о статусе выполняемых задач (для
обеспечения обратной связи)
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
21
Пример реализации пула потоков
ThreadPoolTask
+ ThreadPoolTask()
prepare()
finish()
interrupted()
go()
getName()
-listener
TaskListener
-task
+ taskInterrupted(t : Task) : void
+ taskFinished(t : Task) : void
+ taskStarted(t : Task) : void
Task
+ getName()
+ performWork()
ThreadPool
+
+
+
+
+
+
+
Countdown
taskStarted(t : Task) : void
taskFinished(t : Task) : void
taskInterrupted(t : Task) : void
addTask(t : Task) : void
addTask(t : Task, l : TaskListener) : void
ThreadPool()
main(args : Logical View::java::lang::String[]) : void
PooledThread
+ PooledThread()
- performTask()
+ run()
-taskQueue
-taskQueue
List
-availableThreads
(from util)
Set
(from util)
Новосибирск, 2004
(С) Всеволод Рылов, все права защищены
22
Клиент :
TaskListener
Задача :
Task
:
ThreadPool
: ThreadPoolTask
: PooledThread
: List
<<create>>
PooledThread(Logical View::java::lang::String, List)
<<create>>
addTask(Task, TaskListener)
ThreadPoolTask(Task, TaskListener)
add()
taskStarted(Task)
performWork( )
taskFinished(Task)
Новосибирск, 2004
remove()
prepare( )
go( )
finish( )
(С) Всеволод Рылов, все права защищены
23
Работа потоков с памятью
JVM Main memory
Master copy of V
Master copy of W
write
read
read
read
Thread T2 working
memory
load
Thread T1 working memory
load
store load
Working
copy of V
use
Working
copy of W
use
Операции над
главной
памятью:
read, write, lock,
unlock
lock/unlock
Working
copy of W
Операции
над рабочей
памятью:
use, assign,
load, store
use
assign
Thread T1 execution
engine
Новосибирск, 2004
Thread T2 execution
engine
(С) Всеволод Рылов, все права защищены
24
Download