И.Н. Блинов, В.С. Романчик - Основы программирования на языке Java (1160783), страница 11
Текст из файла (страница 11)
Для предотвращения такой ситуации используется ключевое слово synchronized.// пример #6 : освобождение ресурсов апплетом : AppletThread.javaimport java.applet.*;import java.awt.*;import java.awt.event.*;public class AppletThread extends Applet implements Runnable {final Font font = new Font("Arial", Font.BOLD, 40);String msg = "Java 2";Thread t = null;boolean stop;public void init() {setBackground(Color.blue);setForeground(Color.yellow);}public void start() {t = new Thread(this);stop = false;t.start(); }public void run() {char ch;while(true){try{ repaint();Thread.sleep(300);ch = msg.charAt(0);msg = msg.substring(1, msg.length()); msg += ch;if(stop) break;} catch(InterruptedException e){}68}}public void paint(Graphics g) {g.setFont(font);g.drawString(msg,50,50);}public void stop() {stop = true; t = null; }}Рассмотрим класс TwoThread, в котором создается два потока.
Вэтом же классе создаётся экземпляр класса SourceValue, содержащийпеременную типа String. Экземпляр SourceValue передается в качестве параметра обоим потокам. Первый поток добавляет экземпляркласса SourceValue, а второй извлекает его. Для избежания одновременных действий методы, осуществляющие чтение и запись переменной, объявляются synchronized. Синхронизированный метод изолирует объект, содержащий этот метод, после чего объект становится недоступным для других потоков.
Изоляция снимается, когда потокполностью выполнит соответствующий метод. Другой способ снятияизоляции – вызов метода wait() из изолированного метода.// пример #7 : синхронизированные потоки : TwoThread.javaimport java.util.*;import java.awt.event.*;public class TwoThread{public static void main(String[] args){SourceValue sv = new SourceValue();ThreadB t1 = new ThreadB(sv, "добавление");ThreadB t2 = new ThreadB(sv, "извлечение");t1.start();t2.start();}}class ThreadB implements Runnable{SourceValue res;String name;ThreadB (SourceValue res , String name){this.name = name;this.res = res;}public void run(){int j = 0;while (true){69if (name.equals("добавление")){res.addSource("значение: " + j);j++;if(j == 5) break;}else System.out.println("это значение: "+res.getSource());try{sleep(100);}catch(InterruptedException e){}}}}Имеется два класса – открытый TwoThread и закрытый ThreadB.Основные действия происходят в классе TwoThread.
Здесь создаетсяэкземпляр класса SourceValue и два экземпляра класса ThreadB, после чего экземпляр SourceValue передаётся обоим экземплярамThreadB (потокам). Метод start() запускает поток и вызывает методrun(). После окончания метода run() поток уничтожается. Внутри запускающего поток метода run() вызывается метод addSource() объекта класса SourceValue, для первого по времени запуска потока иgetSource() – для второго.class SourceValue {String theSource = "";boolean reading = false;public synchronized void addSource(String str){while(reading){try{ wait(); }catch(InterruptedException e){}}System.out.println("добавление: "+str);theSource = str;reading = true;notifyAll();//уведомляет другие потоки о снятии изоляции}public synchronized String getSource(){while(!reading){try{ wait(); } catch(InterruptedException e){}}reading = false;notifyAll();return theSource;}70}Дополнительная переменная reading определяет состояние потокаотносительно операций чтения или записи.
Как только методaddSource() начнет выполняться, он сразу же заблокирует объект. Ипока он изменяет значение переменной, ни один другой поток не может вызвать синхронизированный метод getSource(). После записизначение булевой переменной устанавливается true. Для того чтобыпоток чтения узнал о снятии изоляции, вызывается метод notifyAll().После этого поток чтения может производить свои действия.В следующем примере производится чтение информации из одногофайла и запись в другой файл. Создаются и открываются два различных потока ввода/вывода, каждый из которых соединен с файлом.//пример #8: синхронизированные потоки в файлах: FileThrd.javaimport java.io.*;public class FileThrd{public static void main(String[] args){Files f = new Files();new ThreadForRead(f);new ThreadForWrite(f);}}class ThreadForRead implements Runnable{Files f1;boolean action = true;ThreadForRead (Files f){this.f1 = f;new Thread(this,"ThreadForRead").start();}public void run(){while (action){ action = f1.fileRead(); }}}class ThreadForWrite implements Runnable{Files f2;boolean action = true;ThreadForWrite (Files f) {this.f2 = f;new Thread(this, "ThreadForWrite").start();}public void run(){while(action){ action = f2.fileWrite();}71}}class Files{boolean action = true, NoEof = true, lastByte = false;int size,b;InputStream fInput;OutputStream fOutput;Files(){try{fInput = new FileInputStream("for_read.txt");fOutput = new FileOutputStream("for_write.txt");}catch(FileNotFoundException e){System.out.println("нет файла!");}}synchronized boolean fileRead(){if(!action) try{wait(); }catch(InterruptedException e){}try{b = fInput.read();action = false;System.out.println("прочитан: "+(char)b);size = fInput.available();if(size == 0) {NoEof = false;lastByte = true;fInput.close();}notify();}catch(IOException e){System.out.println("в fileRead"+e);}return NoEof;}synchronized boolean fileWrite(){if(action) try {wait(); }catch(InterruptedException e){};try{if (size == 0){if (lastByte) fOutput.write((char) b);fOutput.close();NoEof = false;72}else{fOutput.write((char) b);action = true;notify();}System.out.println("записан:"+(char)b);} catch(IOException e){System.out.println("в fileWrite"+e);}return NoEof;}}Упражнения1.
class Counter { int count = 0;int increment() { int n=count; count = n + 1; return n; } }Что произойдет, если два потока одновременно вызовут метод increment()?а) ошибка компиляции; б) ничего особенного; в) выведено одинаковое значениедля обоих потоков; г) ConcurrentAccessException; д) в обоих потоках выполнитсяcount = n + 1; в то же время переменная не будет увеличена.2. Cоздать апплет, используя поток: строка движется горизонально, отражаясьот границ апплета и меняя при этом случайным образом свой цвет.3.
Cоздать апплет используя поток: строка движется по диагонали. При достижении границ апплета все символы строки случайным образом меняют регистр.4. Организовать сортировку массива методами Шелла, Хора, пузырька, на основе бинарного дерева, быстрой сортироки в разных потоках.5.
Реализовать сортировку графических объектов, используя алгоритмы из упражнения 4.12. СЕТЕВЫЕ ПРОГРАММЫJava делает сетевое программирование простым благодаря наличию специальных средств и класса Network. Рассмотрим некоторыевиды сетевых приложений. Internet-приложения включают Webбраузер, e-mail, сетевые новости, передачу файлов и telnet. Основнойиспользуемый протокол − TCP/IP.Приложения клиент/сервер используют компьютер, выполняющийспециальную программу − сервер, которая предоставляет услуги другим программам − клиентам. Клиент − это программа, получающаяуслуги от сервера.
Клиент-серверные приложения основаны на использовании верхнего уровня протоколов. На TCP/IP основаны следующие протоколы:HTTP − Hypertext Transfer Protocol (WWW);NNTP − Network News Transfer Protocol (группы новостей);73SMTP − Simple Mail Transfer Protocol (посылка почты);POP3 − Post Office Protocol (чтение почты с сервера);FTP − File Transfer Protocol (протокол передачи файлов);TELNET − Удаленное управление компьютерами;Каждый компьютер по протоколу TCP/IP имеет уникальный IPадрес.
Это 32-битовое число, обычно записываемое как четыре числа,разделенные точками, каждое из которых изменяется от 0 до 255. IPадрес может быть временным и выделяться динамически для каждогоподключения или быть постоянным, как для сервера. Обычно приподключении к компьютеру вместо числового IP адреса используютсясимвольные имена (например − www.bsu.by), называемые именамидомена. Специальная программа DNS (Domain Name Sever) преобразует имя домена в числовой IP-адрес.
Получить IP-адрес в программеможно с помощью объекта класса InetAddress из пакета java.net./*пример #1 : вывод IP-адреса локального компьютера, подключенного к Internet : MyLocal.java */import java.net.*;public class MyLocal {public static void main(String[] args){InetAddress myIP = null;try {myIP = InetAddress.getLocalHost();}catch (UnknownHostException e) {}System.out.println(myIP);}}Метод getLocalHost() класса InetAddress создает объект myIP ивозвращает IP-адрес.Следующая программа демонстрирует, как получить IP-адрес изимени домена с помощью сервера имен доменов (DNS), к которомуобращается метод getByName()./*пример #2 : извлечение IP-адреса из имени домена :IPfromDNS.java */import java.net.*;public class IPfromDNS {public static void main(String[] args){InetAddress bsu = null;try {bsu = InetAddress.getByName("www.bsu.by"); }74catch (UnknownHostException e){ }System.out.println(bsu);}}Будет выведено: www.bsu.by/217.21.43.2Для явной идентификации услуг к IP-адресу присоединяется номерпорта через двоеточие, например 217.21.43.2:31.