Методы synchronized в Java

Очень часто возникает ситуация, когда несколько потоков, обращающихся к некоторому общему ресурсу, начинают мешать друг другу; более того, они могут повредить этот общий ресурс. Например, когда два потока записывают информа­цию в файл/объект/поток. Для предотвращения такой ситуации может использоваться ключевое слово synchronized. Синхронизации не требуют только атомарные процессы по записи/чтению, не превышающие по объему 32 бит.

В качестве примера будет рассмотрен процесс записи информации в файл двумя конкурирующими потоками. В методе main() классa SynchroThreads создаются два потока. В этом же методе создается экземпляр класса Synchro, содержащий поле типа FileWriter, связанное с файлом на диске. Экземпляр Synchro передается в качестве параметра обоим потокам. Первый поток записывает строку методом writing() в экземпляр класса Synchro. Второй поток также пытается сделать запись строки в тот же самый объект Synchro. Для избежания одновременной записи такие методы объявляются как synchronized. Синхронизированный метод изолирует объект, после чего объект становится недоступным для других потоков. Изоляция снимается, когда поток полностью выполнит соответствующий метод. Другой способ снятия изоляции – вызов метода wait() из изолированного метода.

В примере продемонстрирован вариант синхронизации файла для защиты от одновременной записи информации в файл двумя различными потоками.

/* пример # 8 : синхронизация записи информации в файл : MyThread.java : Synchro.java : SynchroThreads.java */

package chapt14;

import java.io.*;

public class Synchro {

private FileWriter fileWriter;

public Synchro(String file) throws IOException {

fileWriter = new FileWriter(file, true);

}

public void close() {

try {

fileWriter.close();

} catch (IOException e) {

e.printStackTrace();

}

}

public synchronized void writing(String str, int i) {

try {

System.out.print(str + i);

fileWriter.append(str + i);

Thread.sleep((long)(Math.random() * 50));

System.out.print("->" + i + " ");

fileWriter.append("->" + i + " ");

} catch (IOException e) {

System.err.print("ошибка файла");

e.printStackTrace();

} catch (InterruptedException e) {

System.err.print("ошибка потока");

e.printStackTrace();

}

}

}

package chapt14;

public class MyThread extends Thread {

private Synchro s;

public MyThread(String str, Synchro s) {

super(str);

this.s = s;

}

public void run() {

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

s.writing(getName(), i);

}

}

}

package chapt14;

import java.io.*;

public class SynchroThreads {

public static void main(String[] args) {

try {

Synchro s = new Synchro("c:\\temp\\data.txt");

MyThread t1 = new MyThread("First", s);

MyThread t2 = new MyThread("Second", s);

t1.start();

t2.start();

t1.join();

t2.join();

s.close();

} catch (IOException e) {

System.err.print("ошибка файла");

e.printStackTrace();

} catch (InterruptedException e) {

System.err.print("ошибка потока");

e.printStackTrace();

}

}

}

В результате в файл будет выведено:

First0->0 Second0->0 First1->1 Second1->1 First2->2

Second2->2 First3->3 Second3->3 First4->4 Second4->4

Код построен таким образом, что при отключении синхронизации метода writing() при его вызове одним потоком другой поток может вклиниться и произвести запись своей информации, несмотря на то, что метод не завершил запись, инициированную первым потоком.

Вывод в этом случае может быть, например, следующим:

First0Second0->0 Second1->0 First1->1 First2->1 Second2->2 First3->3 First4->2 Second3->3 Second4->4 ->4

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100