Upload
yandex
View
5.455
Download
3
Embed Size (px)
DESCRIPTION
О.В.Сухорослов "Многопотчное программирование. Часть 2", 24.02.2012, место показа МФТИ, Школа анализа данных (ШАД)
Citation preview
02 Многопоточное программирование
О.В. Сухорослов
24.02.2011
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 1 / 61
Синхронизация
Безопасный доступ к общим даннымВзаимное исключение и memory barrier (см. лекцию 1)
Координация действий между потокамиУсловная синхронизация
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 2 / 61
Синхронизация
Безопасный доступ к общим даннымВзаимное исключение и memory barrier (см. лекцию 1)
Координация действий между потокамиУсловная синхронизация
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 2 / 61
Поиск шаблона в тексте
lecture2.textsearch.SeqTextSearch1 public class SeqTextSearch {2 ...34 public static void main(String [] args) {5 long start = System.currentTimeMillis ();6 try {7 String filePath = args [0];8 String pattern = args [1];9
10 List <String > text = readFile(filePath );11 List <String > results = search(text , pattern );1213 System.out.println(14 "Found " + results.size() + " matches:");15 ...16 } catch (Exception e) {17 e.printStackTrace ();18 }19 long end = System.currentTimeMillis ();20 System.out.println("Total time: " + (end - start) + " ms");21 }22 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 3 / 61
Запуск
XML-файл, 370 MbPattern: ‘[\w-\.]+@([\w-]+\.){1,2}[a-zA-Z]{2,4}‘
Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 4 / 61
OutOfMemoryError
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java :2760)at java.util.Arrays.copyOf(Arrays.java :2734)at java.util.ArrayList.ensureCapacity(ArrayList.java :167)at java.util.ArrayList.add(ArrayList.java :351)at lecture2.textsearch.SeqTextSearch.readFile(SeqTextSearch.java :22)at lecture2.textsearch.SeqTextSearch.main(SeqTextSearch.java :54)
java -Xms<initial heap size> -Xmx<maximum heap size>java -Xms256m -Xmx256mjava -Xms2g -Xmx2gEclipse: Run / Arguments / VM arguments
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 5 / 61
SearchTask
lecture2.textsearch.ParallelTextSearch1.SearchTask1 static class SearchTask implements Runnable {23 private List <String > text;4 private int from , to;5 private Pattern regex;6 public List <String > results;78 public SearchTask(List <String > text , int from , int to ,9 Pattern regex) {
10 ...11 }1213 public void run() {14 Matcher matcher;15 for (int i = from; i <= to; i++) {16 matcher = regex.matcher(text.get(i));17 while (matcher.find ()) {18 results.add (...);19 }20 }21 }22 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 7 / 61
ParallelTextSearch1 (main)
lecture2.textsearch.ParallelTextSearch11 public static void main(String [] args) {2 ...3 List <String > text = SeqTextSearch.readFile(filePath );4 ...5 SearchTask task1 = new SearchTask(6 text , 0, text.size() / 2 - 1, regex);7 SearchTask task2 = new SearchTask(8 text , text.size() / 2, text.size() - 1, regex);9 Thread thread1 = new Thread(task1);
10 Thread thread2 = new Thread(task2);11 thread1.start ();12 thread2.start ();1314 thread1.join();15 thread2.join();1617 ...18 task1.results.addAll(task2.results );19 System.out.println(20 "Found " + task1.results.size() + " matches");21 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 8 / 61
Запуск ParallelTextSearch1
Read time: 8437 msSearch time: 26034 msFound 98 matchesTotal time: 34472 ms
Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 9 / 61
BaseBoundedBuffer
lecture2.textsearch.BaseBoundedBuffer1 public abstract class BaseBoundedBuffer <T> {2
3 private final T[] buf;4 private int tail;5 private int head;6 private int count;7
8 protected BaseBoundedBuffer(int capacity) {9 this.buf = (T[]) new Object[capacity ];
10 }11
12 protected synchronized final void doPut(T v) {13 buf[tail] = v;14 if (++ tail == buf.length)15 tail = 0;16 ++count;17 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 12 / 61
BaseBoundedBuffer (2)
lecture2.textsearch.BaseBoundedBuffer1 protected synchronized final T doTake () {2 T v = buf[head];3 buf[head] = null;4 if (++ head == buf.length)5 head = 0;6 --count;7 return v;8 }9
10 public synchronized final boolean isFull () {11 return count == buf.length;12 }13
14 public synchronized final boolean isEmpty () {15 return count == 0;16 }17
18 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 13 / 61
PollingQueue
lecture2.textsearch.PollingQueue1 public class PollingQueue <T> extends BaseBoundedBuffer <T> {2 ...3 public void put(T v) throws InterruptedException {4 while (true) {5 synchronized (this) {6 if (! isFull ()) {7 doPut(v);8 return;9 }
10 }11 Thread.sleep(SLEEP_TIME );12 }13 }1415 public T take() throws InterruptedException {16 while (true) {17 synchronized (this) {18 if (! isEmpty ())19 return doTake ();20 }21 Thread.sleep(SLEEP_TIME );22 }23 }24 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 14 / 61
WaitNotifyQueue
lecture2.textsearch.WaitNotifyQueue1 public class WaitNotifyQueue <T> extends BaseBoundedBuffer <T> {23 public WaitNotifyQueue(int size) {4 super(size);5 }67 public synchronized void put(T v) throws InterruptedException {8 while (isFull ())9 wait ();
10 doPut(v);11 notifyAll ();12 }1314 public synchronized T take() throws InterruptedException {15 while (isEmpty ())16 wait ();17 T v = doTake ();18 notifyAll ();19 return v;20 }2122 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 15 / 61
java.util.concurrent.locks.Condition
Condition condition = lock.newCondition()
condition.await()await(long time, TimeUnit unit)awaitUntil(Date deadline)
condition.signal() / signallAll()
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 16 / 61
ConditionQueue
lecture2.textsearch.ConditionQueue1 public class ConditionQueue <T> {23 protected final Lock lock = new ReentrantLock ();4 private final Condition notFull = lock.newCondition ();5 private final Condition notEmpty = lock.newCondition ();6 private final T[] buf;7 private int tail , head , count;89 protected ConditionQueue(int capacity) {
10 this.buf = (T[]) new Object[capacity ];11 }1213 public void put(T x) throws InterruptedException {14 lock.lock ();15 try {16 while (count == buf.length)17 notFull.await ();18 buf[tail] = x;19 if (++ tail == buf.length)20 tail = 0;21 ++count;22 notEmpty.signal ();23 } finally {24 lock.unlock ();25 }26 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 17 / 61
ConditionQueue (2)
lecture2.textsearch.ConditionQueue1 public T take() throws InterruptedException {2 lock.lock ();3 try {4 while (count == 0)5 notEmpty.await ();6 T x = buf[head];7 buf[head] = null;8 if (++ head == buf.length)9 head = 0;
10 --count;11 notFull.signal ();12 return x;13 } finally {14 lock.unlock ();15 }16 }17 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 18 / 61
Reader.run()
lecture2.textsearch.ParallelTextSearch2.Reader.run()1 try {2 input = new BufferedReader(3 new InputStreamReader(new FileInputStream(filePath )));4 String line = null;5 int lineNum = 0;6 while ((line = input.readLine ()) != null) {7 queue.put(new TextLine(lineNum ,line ));8 lineNum ++;9 }
10 } catch (IOException e) {11 e.printStackTrace ();12 } finally {13 queue.put(null); // poison pill14 ...15 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 19 / 61
Searcher.run()
lecture2.textsearch.ParallelTextSearch2.Searcher.run()1 Matcher matcher;2 TextLine line;34 while (true) {5 line = queue.take ();6 if (line != null) {7 matcher = regex.matcher(line.getText ());8 while (matcher.find ()) {9 results.add (...);
10 }11 } else break;12 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 20 / 61
ParallelTextSearch2
lecture2.textsearch.ParallelTextSearch2.main()1 WaitNotifyQueue <TextLine > queue =2 new WaitNotifyQueue <TextLine >(1000);34 Reader reader = new Reader(filePath , queue );5 reader.start ();67 Searcher searcher = new Searcher(queue , pattern );8 searcher.start ();9
10 reader.join ();11 searcher.join ();
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 21 / 61
Запуск ParallelTextSearch2
Read time: 53228 msSearch time: 53246 msFound 98 matchesTotal time: 53251 ms
Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 22 / 61
ParallelTextSearch3
lecture2.textsearch.ParallelTextSearch3.main()1 WaitNotifyQueue <List<TextLine>> queue =2 new WaitNotifyQueue <List<TextLine>>(QUEUE_SIZE );34 Reader reader = new Reader(filePath , queue );5 reader.start ();67 Searcher searcher = new Searcher(queue , pattern );8 searcher.start ();9
10 reader.join ();11 searcher.join ();
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 23 / 61
Запуск ParallelTextSearch3
QUEUE_SIZE = 1000SPLIT_SIZE = 1000
Read time: 38131 msSearch time: 42837 msFound 98 matchesTotal time: 42841 ms
Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 24 / 61
Готовые реализации очередей
Интерфейс BlockingQueue
РеализацииLinkedBlockingQueueArrayBlockingQueuePriorityBlockingQueueSynchronousQueueDelayQueue
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 25 / 61
ParallelTextSearch4
lecture2.textsearch.ParallelTextSearch4.main()1 BlockingQueue <List <TextLine >> queue =2 new ArrayBlockingQueue <List <TextLine >>( QUEUE_SIZE );34 Reader reader = new Reader(filePath , queue );5 reader.start ();67 Searcher searcher = new Searcher(queue , pattern );8 searcher.start ();9
10 reader.join ();11 searcher.join ();
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 26 / 61
Запуск ParallelTextSearch4
QUEUE_SIZE = 100SPLIT_SIZE = 1000
Read time: 41502 msSearch time: 41989 msFound 98 matchesTotal time: 41992 ms
Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 27 / 61
ParallelTextSearch5
Пул потоков, ведущих поиск в фрагментах текста
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 28 / 61
Executor
1 Executor executor = ...;2 executor.execute(new RunnableTask1 ());3 executor.execute(new RunnableTask2 ());4 ...
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 29 / 61
Простые примеры
1 class DirectExecutor implements Executor {2 public void execute(Runnable r) {3 r.run();4 }5 }
1 class ThreadPerTaskExecutor implements Executor {2 public void execute(Runnable r) {3 new Thread(r).start ();4 }5 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 30 / 61
Простые примеры
1 class DirectExecutor implements Executor {2 public void execute(Runnable r) {3 r.run();4 }5 }
1 class ThreadPerTaskExecutor implements Executor {2 public void execute(Runnable r) {3 new Thread(r).start ();4 }5 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 30 / 61
Интерфейсы ExecutorService, Callable и Future
ExecutorServiceshutdown(), shutdownNow()Future<T> submit(Callable<T> task)
Callable<T>T call()
Future<T>boolean isDone()T get() / get(long timeout, TimeUnit unit)boolean cancel(boolean mayInterruptIfRunning)
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 31 / 61
Интерфейсы ExecutorService, Callable и Future
ExecutorServiceshutdown(), shutdownNow()Future<T> submit(Callable<T> task)
Callable<T>T call()
Future<T>boolean isDone()T get() / get(long timeout, TimeUnit unit)boolean cancel(boolean mayInterruptIfRunning)
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 31 / 61
Интерфейсы ExecutorService, Callable и Future
ExecutorServiceshutdown(), shutdownNow()Future<T> submit(Callable<T> task)
Callable<T>T call()
Future<T>boolean isDone()T get() / get(long timeout, TimeUnit unit)boolean cancel(boolean mayInterruptIfRunning)
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 31 / 61
Пул потоков
1 ThreadPoolExecutor(int corePoolSize ,2 int maximumPoolSize ,3 long keepAliveTime ,4 TimeUnit unit ,5 BlockingQueue <Runnable > workQueue)
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 32 / 61
Фабрика Executors
newCachedThreadPool()newFixedThreadPool(int nThreads)newSingleThreadExecutor()newScheduledThreadPool(int corePoolSize)...
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 33 / 61
SearchTask
lecture2.textsearch.ParallelTextSearch5.SearchTask1 static class SearchTask implements Callable <List <String >> {23 private List <TextLine > lines;4 private Pattern regex;56 public SearchTask(List <TextLine > split , Pattern regex) {7 this.lines = split;8 this.regex = regex;9 }
1011 public List <String > call() {12 List <String > results = new ArrayList <String >();13 for (TextLine line : lines) {14 Matcher matcher = regex.matcher(line.getText ());15 while (matcher.find ()) {16 results.add (...);17 }18 }19 return results;20 }21 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 34 / 61
ParallelTextSearch5
lecture2.textsearch.ParallelTextSearch5.main()1 exec = Executors.newFixedThreadPool(2 Runtime.getRuntime (). availableProcessors ());34 List <Future <List <String >>> results = new ...5 ...6 while ((line = input.readLine ()) != null) {7 split.add(new TextLine(lineNum , line ));8 if (split.size() == SPLIT_SIZE) {9 Future <List <String >> f =
10 exec.submit(new SearchTask(split , regex ));11 results.add(f);12 split = new ArrayList <TextLine >( SPLIT_SIZE );13 }14 lineNum ++;15 }1617 if (split.size() > 0) {18 Future <List <String >> f = exec.submit (...);19 results.add(f);20 }2122 int matchCount = 0;23 for (Future <List <String >> result : results) {24 matchCount += result.get(). size ();25 }2627 System.out.println("Found " + matchCount + " matches");
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 35 / 61
Запуск ParallelTextSearch5
24 ядраSPLIT_SIZE = 100
24 processorsFound 98 matchesTotal time: 8485 ms
Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 36 / 61
Как сделать поиск еще быстрее?
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 37 / 61
java.util.concurrent.CyclicBarrier
CyclicBarrier(int parties)CyclicBarrier(int parties, Runnable barrierAction)
barrier.await() : arrival index (N-1,...,0)InterruptedExceptionBrokenBarrierException
getNumberWaiting()reset()...
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 39 / 61
java.util.concurrent.CyclicBarrier
CyclicBarrier(int parties)CyclicBarrier(int parties, Runnable barrierAction)
barrier.await() : arrival index (N-1,...,0)InterruptedExceptionBrokenBarrierException
getNumberWaiting()reset()...
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 39 / 61
java.util.concurrent.CyclicBarrier
CyclicBarrier(int parties)CyclicBarrier(int parties, Runnable barrierAction)
barrier.await() : arrival index (N-1,...,0)InterruptedExceptionBrokenBarrierException
getNumberWaiting()reset()...
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 39 / 61
Алгоритм Флойда
1 for (k=0; k<N; k++) {2 for (i=0; i<N; i++) {3 for (j=0; j<N; j++) {4 A[i][j] = Math.min(A[i][j], A[i][k]+A[k][j]);5 }6 }7 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 40 / 61
FloydCycBarrier
lecture2.floyd.FloydCycBarrier1 public static void main(String [] args) {2 int [][] A = GraphGenerator.generate (1000);3 ExecutorService exec =4 Executors.newFixedThreadPool(numThreads );5 try {6 CyclicBarrier b = new CyclicBarrier(numThreads + 1);78 for (int i = 0; i < numThreads; i++) {9 exec.execute(new FloydTask(A, i, b));
10 }1112 for (int k = 0; k < A.length; k++) {13 b.await ();14 // System.out.println (" Iteration " + k);15 }16 } catch (Exception e) {17 e.printStackTrace ();18 } finally {19 exec.shutdown ();20 }21 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 41 / 61
FloydTask
lecture2.floyd.FloydCycBarrier.FloydTask1 static class FloydTask implements Runnable {2 ...34 public void run() {5 try {6 int i, j, k;7 for (k = 0; k < A.length; k++) {8 for (i = t; i < A.length; i += numThreads) {9 for (j = 0; j < A.length; j++) {
10 A[i][j] =11 Math.min(A[i][j], A[i][k] + A[k][j]);12 }13 }14 b.await ();15 }16 } catch (InterruptedException e) {17 } catch (BrokenBarrierException e) {18 e.printStackTrace ();19 }20 }21 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 42 / 61
Число итераций не известно? (вариант 1)
1 // wait for all threads to finish iteration2 int myNum = b.await ();3
4 // last thread checks stop condition5 if (myNum == 0) {6 // check condition , set done flag ...7 }8
9 // sync after condition check10 b.await ();
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 43 / 61
Число итераций не известно? (вариант 2)
1 barrier = new CyclicBarrier(N,2 new Runnable () {3 public void run() {4 // check condition , set done flag ...5 }6 );
Действие выполняется при достижении барьера всеми потоками,перед тем как разблокировать их
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 44 / 61
Домашнее задание (ДЗ №1, Задача 2)
Напишите многопоточный поисковый робот, реализующий обходWeb-графа в ширину и сохраняющий на диск все посещенныестраницы
При запуске роботу передаются URL начальной страницы иглубина обходаРобот не должен посещать одну и ту же страницу более одногораза
Попытайтесь добиться максимальной скорости работы робота,обоснуйте используемый для этого подход
Заготовка для робота: lecture2.crawler.CrawlerUtils (см. код клекции)
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 45 / 61
Дополнительный материал
Maurice Herlihy, Nir Shavit. The Art of Multiprocessor Programming.Morgan Kaufmann, 2008
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 46 / 61
Lock
1 public interface Lock {2 public void lock (); // before entering critical section3 public void unlock (); // before leaving critical section4 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 47 / 61
LockOne
1 class LockOne implements Lock {2 private volatile boolean [] flag = new boolean [2]; // ERROR3 // thread -local index , 0 or 145 public void lock() {6 int i = ThreadID.get();7 int j = 1 - i;8 flag[i] = true;9 while (flag[j]) {} // wait
10 }1112 public void unlock () {13 int i = ThreadID.get();14 flag[i] = false;15 }16 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 48 / 61
LockTwo
1 class LockTwo implements Lock {2 private volatile int victim;34 public void lock() {5 int i = ThreadID.get();6 victim = i; // let the other go first7 while (victim == i) {} // wait8 }9
10 public void unlock () {}11 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 49 / 61
PetersonLock
1 class Peterson implements Lock {2 // thread -local index , 0 or 13 private volatile boolean [] flag = new boolean [2]; // ERROR4 private volatile int victim;56 public void lock() {7 int i = ThreadID.get();8 int j = 1 - i;9 flag[i] = true; // I’m interested
10 victim = i; // you go first11 while (flag[j] && victim == i) {}; // wait12 }1314 public void unlock () {15 int i = ThreadID.get();16 flag[i] = false; // I’m not interested17 }18 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 50 / 61
Filter Lock
1 class Filter implements Lock {2 AtomicIntegerArray level; // volatile int[] level;3 AtomicIntegerArray victim; // volatile int[] victim;45 public Filter(int n) {6 level = new int[n];7 victim = new int[n]; // use 1..n-18 for (int i = 0; i < n; i++) {9 level[i] = 0;
10 }11 }12 public void lock() {13 int me = ThreadID.get ();14 for (int i = 1; i < n; i++) { // attempt level 115 level[me] = i;16 victim[i] = me;17 // spin while conflicts exist18 while (( EXISTS k != me) (level[k] >= i && victim[i] == me)) {};19 }20 }21 public void unlock () {22 int me = ThreadID.get ();23 level[me] = 0;24 }25 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 51 / 61
Lamport’s Bakery Algorithm
1 class Bakery implements Lock {2 volatile boolean [] flag; // ERROR3 volatile Label[] label; // ERROR4 public Bakery (int n) {5 flag = new boolean[n];6 label = new Label[n];7 for (int i = 0; i < n; i++) {8 flag[i] = false; label[i] = 0;9 }
10 }11 public void lock() {12 int i = ThreadID.get();13 flag[i] = true;14 label[i] = max(label[0], ..., label[n-1]) + 1;15 while (( EXISTS k != i)(flag[k] && (label[k],k) << (label[i],i))) {};16 }17 public void unlock () {18 flag[ThreadID.get()] = false;19 }20 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 52 / 61
Важная теорема
Любой алгоритм, решающий задачу взаимного исключения для Nпотоков (с гарантией от deadlock) путем чтения и записи памяти,должен использовать как минимум N адресов памяти
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 53 / 61
Test-And-Set-Lock
1 public class TASLock implements Lock {2 AtomicBoolean state = new AtomicBoolean(false );34 public void lock() {5 while (state.getAndSet(true)) {}6 }78 public void unlock () {9 state.set(false);
10 }11 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 55 / 61
Test-Test-And-Set-Lock
1 public class TTASLock implements Lock {2 AtomicBoolean state = new AtomicBoolean(false );34 public void lock() {5 while (true) {6 while (state.get()) {};7 if (!state.getAndSet(true))8 return;9 }
10 }1112 public void unlock () {13 state.set(false);14 }15 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 56 / 61
BackoffLock
1 public class BackoffLock implements Lock {2 private AtomicBoolean state = new AtomicBoolean(false );3 private static final int MIN_DELAY = ...;4 private static final int MAX_DELAY = ...;5 public void lock() {6 Backoff backoff = new Backoff(MIN_DELAY , MAX_DELAY );7 while (true) {8 while (state.get()) {};9 if (!state.getAndSet(true)) {
10 return;11 } else {12 backoff.backoff ();13 }14 }15 }16 public void unlock () {17 state.set(false);18 }19 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 57 / 61
Backoff
1 public class Backoff {2 final int minDelay , maxDelay;3 int limit;4 final Random random;56 public Backoff(int min , int max) {7 minDelay = min;8 maxDelay = min;9 limit = minDelay;
10 random = new Random ();11 }1213 public void backoff () throws InterruptedException {14 int delay = random.nextInt(limit);15 limit = Math.min(maxDelay , 2 * limit );16 Thread.sleep(delay);17 }18 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 58 / 61
MCSLock (1)
1 public class MCSLock implements Lock {2 AtomicReference <QNode > tail;3 ThreadLocal <QNode > myNode;4 public MCSLock () {5 queue = new AtomicReference <QNode >(null);6 myNode = new ThreadLocal <QNode >() {7 protected QNode initialValue () {8 return new QNode ();9 }
10 };11 }12 ...13 class QNode {14 boolean locked = false;15 QNode next = null;16 }17 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 59 / 61
MCSLock (2)
1 public void lock() {2 QNode qnode = myNode.get();3 QNode pred = tail.getAndSet(qnode );4 if (pred != null) {5 qnode.locked = true;6 pred.next = qnode;7 // wait until predecessor gives up the lock8 while (qnode.locked) {}9 }
10 }11 public void unlock () {12 QNode qnode = myNode.get();13 if (qnode.next == null) {14 if (tail.compareAndSet(qnode , null))15 return;16 // wait until predecessor fills in its next field17 while (qnode.next == null) {}18 }19 qnode.next.locked = false;20 qnode.next = null;21 }
О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 60 / 61