300 likes | 673 Views
Java Synchronization ~. Synchronized, wait(), notify() statements Multiple Notifications Block Synchronization Java Semaphores Java Monitors. Java Synchronization ~. Thread safe: 여러 thread 에 의해 동시에 접근되어도 데이터의 일관성( data consistency) 을 보장할 수 있을 때 Synchronized Statement
E N D
Java Synchronization ~ • Synchronized, wait(), notify() statements • Multiple Notifications • Block Synchronization • Java Semaphores • Java Monitors 2000 운영체제
Java Synchronization ~ • Thread safe: 여러 thread에 의해 동시에 접근되어도 데이터의 일관성(data consistency)을 보장할 수 있을 때 • Synchronized Statement • Every object has a lock associated with it. • Calling a synchronized method requires “owning” the lock. • If a calling thread does not own the lock (another thread already owns it), the calling thread is placed in the wait set for the object’s lock. • The lock is released when a thread exits the synchronized method. 2000 운영체제
Java Synchronization ~ • Entry Set 2000 운영체제
Java Synchronization ~ <synchronized 와 yield() 이용한 Bounded Buffer> : deadlock 가능 (어떻게? 왜?) • Synchronized enter() Method public synchronized void enter(Object item) { while (count == BUFFER_SIZE) Thread.yield(); ++count; buffer[in] = item; in = (in + 1) % BUFFER_SIZE; } • Synchronized remove() Method • public synchronized Object remove() { • Object item; • while (count == 0) • Thread.yield(); • --count; • item = buffer[out]; • out = (out + 1) % BUFFER_SIZE; • return item; • } • The wait() Method • When a thread calls wait(), the following occurs: • - the thread releases the object lock. • - thread state is set to blocked. • - thread is placed in the wait set. 2000 운영체제
Java Synchronization ~ • Entry and Waits Set 2000 운영체제
Java Synchronization ~ • Notify Method When a thread calls notify(), the following occurs: - selects an arbitrary thread T from the wait set. - moves T to the entry set. - sets T to Runnable. T can now compete for the object’s lock again. 2000 운영체제
Java Synchronization ~ <synchronized, wait(), notify() 이용한 Bounded Buffer> • enter() with wait/notify Methods public synchronized void enter(Object item) { while (count == BUFFER_SIZE) try { wait(); } catch (InterruptedException e) { } } ++count; buffer[in] = item; in = (in + 1) % BUFFER_SIZE; notify(); } • remove() with wait/notify Methods • public synchronized Object remove() { • Object item; • while (count == 0) • try { • wait(); • } • catch (InterruptedException e) { } • --count; • item = buffer[out]; • out = (out + 1) % BUFFER_SIZE; • notify(); • return item; • } 2000 운영체제
Java Synchronization ~ • Bounded Buffer 완전한 해법 public class BoundedBufferServer { public static void main(String args[]) { BoundedBuffer server = new BoundedBuffer(); // now create the producer and consumer threads Producer producerThread = new Producer(server); Consumer consumerThread = new Consumer(server); producerThread.start(); consumerThread.start(); } } 2000 운영체제
Java Synchronization ~ import java.util.*; public class Consumer extends Thread { public Consumer(BoundedBuffer b) { buffer = b; } public void run() { Date message; while (true) { BoundedBuffer.napping(); // consume an item from the buffer System.out.println("Consumer wants to consume."); message = (Date)buffer.remove(); } } private BoundedBuffer buffer; } import java.util.*; public class Producer extends Thread { public Producer(BoundedBuffer b) { buffer = b; } public void run() { Date message; while (true) { BoundedBuffer.napping(); // produce an item & enter it into the buffer message = new Date(); System.out.println("Producer produced " + message); buffer.enter(message); } } private BoundedBuffer buffer; } 2000 운영체제
Java Synchronization ~ public class BoundedBuffer { public BoundedBuffer() { // buffer is initially empty count = 0; in = 0; out = 0; buffer = new Object[BUFFER_SIZE]; } // producer and consumer will call this to nap public static void napping() { int sleepTime = (int) (NAP_TIME * Math.random() ); try { Thread.sleep(sleepTime*1000); } catch(InterruptedException e) { } } public synchronized void enter(Object item) {…}; public synchronized Object remove() {…}; public static final int NAP_TIME = 5; private static final int BUFFER_SIZE = 5; private int count; // number of items in the buffer private int in; // points to the next free position in the buffer private int out; // points to the next full position in the buffer private Object[] buffer; } 2000 운영체제
Java Synchronization ~ public synchronized Object remove() { Object item; while (count == 0) { try { wait(); } catch (InterruptedException e) { } } // remove an item from the buffer --count; item = buffer[out]; out = (out + 1) % BUFFER_SIZE; if (count == 0) System.out.println("Consumer Consumed " + item + " Buffer EMPTY"); else System.out.println("Consumer Consumed " + item + " Buffer Size = " + count); notify(); return item; } public synchronized void enter(Object item) { while (count == BUFFER_SIZE) { try { wait(); } catch (InterruptedException e) { } } // add an item to the buffer ++count; buffer[in] = item; in = (in + 1) % BUFFER_SIZE; if (count == BUFFER_SIZE) System.out.println("Producer Entered “ + item + " Buffer FULL"); else System.out.println("Producer Entered “ + item + " Buffer Size = " + count); notify(); } 2000 운영체제
Java Synchronization ~ <Readers-Writers> • Database class with Java Synchronization public class Database { public Database() { readerCount = 0; dbReading = false; dbWriting = false; } public synchronized int startRead() { /* see next slides */ } public synchronized int endRead() { /* see next slides */ } public synchronized void startWrite() { /* see next slides */ } public synchronized void endWrite() { /* see next slides */ } private int readerCount; private boolean dbReading; private boolean dbWriting; } 2000 운영체제
Java Synchronization ~ • Writer Method • public synchronized void startWrite() { • while (dbReading == true || dbWriting == true) • try { • wait(); • } • catch (InterruptedException e) { } • dbWriting = true; • } • public synchronized void endWrite() { • dbWriting = false; • notifyAll(); • } • Reader Methods public synchronized int startRead() { while (dbWriting == true) { try { wait(); } catch (InterruptedException e) { } } ++readerCount; if (readerCount == 1) dbReading = true; return readerCount; } public synchronized int endRead() { --readerCount if (readerCount == 0) dbReading = false; notifyAll(); return readerCount; } 2000 운영체제
Java Synchronization public class Reader extends Thread { public Reader(int r, Database db) { readerNum = r; server = db; } public void run() { int c; while (true) { System.out.println("reader " + readerNum + " is sleeping."); Database.napping(); System.out.println("reader " + readerNum + " wants to read."); c = server.startRead(readerNum); // you have access to read from the database System.out.println("reader " + readerNum + " is reading. Count = " + c); Database.napping(); c = server.endRead(readerNum); System.out.println("reader " + readerNum + " is done reading. Count = " + c); } } private Database server; private int readerNum; } 2000 운영체제
Java Synchronization public class Writer extends Thread { public Writer(int w, Database db) { writerNum = w; server = db; } public void run() { while (true) { System.out.println("writer " + writerNum + " is sleeping."); Database.napping(); System.out.println("writer " + writerNum + " wants to write."); server.startWrite(writerNum); // you have access to write to the database System.out.println("writer " + writerNum + " is writing."); Database.napping(); server.endWrite(writerNum); System.out.println("writer " + writerNum + " is done writing."); } } private Database server; private int writerNum; } 2000 운영체제
Java Synchronization public class ReaderWriterServer { public static void main(String args[]) { Database server = new Database(); Reader[] readerArray = new Reader[NUM_OF_READERS]; Writer[] writerArray = new Writer[NUM_OF_WRITERS]; for (int i = 0; i < NUM_OF_READERS; i++) { readerArray[i] = new Reader(i, server); readerArray[i].start(); } for (int i = 0; i < NUM_OF_WRITERS; i++) { writerArray[i] = new Writer(i, server); writerArray[i].start(); } } private static final int NUM_OF_READERS = 3; private static final int NUM_OF_WRITERS = 2; } 2000 운영체제
Multiple Notifications • notify() selects an arbitrary thread from the wait set. *This may not be the thread that you want to be selected. • Java does not allow you to specify the thread to be selected. • notifyAll() removes ALL threads from the wait set and places them in the entry set. This allows the threads to decide among themselves who should proceed next. • notifyAll() is a conservative strategy that works best when multiple threads may be in the wait set. 2000 운영체제
DoWork() ~ public class DoWork { // pnum is the number of the thread that wishes to do some work public synchronized void DoWork(int pnum) { while (turn != pnum) { try { wait(); } catch (InterruptedException e) {} } // do some work for awhile System.out.println("Worker " + pnum + " will do some work"); try { Thread.sleep( (int) (Math.random() * 3000) ); } catch (InterruptedException e) { } // ok, we're finished. Now indicate to the next waiting // thread that it is their turn to do some work. System.out.println("Worker " + pnum + " is done working"); if (turn < 5) ++turn; else turn = 1; // change this to notifyAll() to see it run correctly! notify(); } private int turn = 1; } 2000 운영체제
DoWork() ~ public class TestIt { public static void main(String args[]) { DoWork pile = new DoWork(); Worker[] bees = new Worker[5]; for (int i = 1; i <= 5; i++) bees[i-1] = new Worker(pile, "Worker “ + (new Integer(i)).toString(), i); for (int i = 1; i <= 5; i++) bees[i-1].start(); } } public class Worker extends Thread { public Worker(DoWork p, String n, int i) { pile = p; name = n; num = i; } public void run() { while (true) { Runner.slacking(); pile.DoWork(num); } } private DoWork pile; private String name; private int num; } public class Runner { public static void slacking() { try { Thread.sleep( (int) (Math.random() * 3000) ); } catch (InterruptedException e) { } } } 2000 운영체제
Block Synchronization • Blocks of code – rather than entire methods – may be declared as synchronized. • This yields a lock scope that is typically smaller than a synchronized method. • synchronized block 안에서 wait()와 notify() 사용 가능 Object mutexLock = new Object(); . . . public void someMethod() { // non-critical section synchronized(mutexLock) { // critical section } // non-critical section } 2000 운영체제
Java Semaphores ~ • Java does not provide a semaphore, but a basic semaphore can be constructed using Java synchronization mechanism. public class Semaphore { public Semaphore() { value = 0; } public Semaphore(int v) { value = v; } public synchronized void P() { while (value <= 0) { try { wait(); } catch (InterruptedException e) { } } value --; } public synchronized void V() { ++value; notify(); } private int value; } 2000 운영체제
Linux에서 Wait Queue와 Semaphore • Linux의 세마포어 원자적 연산 구현 • P(S)에서 process status를 TASK_UNINTERRUPTIBLE로 uninterruptible하게 만들고 대기큐에 들어가고 CPU 스케줄러 호출하여 제어를 넘김 • V(S)에서 TASK_RUNNING으로 재활성화 됨 • (Linux Kernel Internals, 2nd Ed., p34~36 참조) struct wait_queue() { Int task_struct *task; struct wait_queue *next; }; struct semaphore() { Int count; struct wait_queue *wait; }; void add_wait_queue(struct wait_queue ** queue, struct wait_queue *entry); void remove_wait_queue(struct wait_queue ** queue, struct wait_queue *entry); 2000 운영체제
Linux에서 Wait Queue와 Semaphore void sleep_on(struct wait_queue **queue) { struct wait_queue entry = {current, NULL}; current->state=TASK_UNINTERRUPTIBLE; add_wait_queue(queue, &entry); schedule(); remove_wait_queue(queue, *entry); } void wake_up(struct wait_queue **queue) { struct wait_queue *p = *queue; do { p->task->state = TASK_RUNNING; p = p->next; } while(p != *queue); } void down(structure semaphore *sem) { while(sem->count <= 0) sleep_on(sem->wait); sem->count--; } void up(structure semaphore *sem) { sem->count++; wake_up(&sem->wait); } 2000 운영체제
Java Semaphores • Java의 동기화 규칙(synchronization rules) • 하나의 thread는 어떤 객체의 lock을 가진 상태에서 그 객체에 대한 다른 synchronized method (또는 block)에 진입할 수 있다. • 하나의 thread는 다른 객체에 대한 synchronized method 호출을 내포(nest)할 수 있다. 즉, 하나의 thread는 동시에 여러개의 다른 객체에 대한 lock을 소유할 수 있다. • synchronized로 선언되어 있지 않은 어떤 객체의 method는 그 객체에 대하여 다른 synchronized method가 실행 중일 지라도 lock의 소유에 상관없이 그 객체에 대한 method를 호출할 수 있다. • 만일 어떤 객체에 대한 wait set가 비어있다면 notify()나 notifyAll()은 아무 영향을 주지 않는다. • Java Monitor • Java synchronization의 lock은 모니터처럼 동작 • 모든 Java 객체는 연관된 monitor를 가짐 • Java는 이름 없는 하나의 조건변수(a unnamed condition variable)를 가지는 모니터 • condition.wait : wait() • condition.signal: notify(), notifyAll() • notify(), notyfyAll()로 깨어난 thread는 스스로 조건이 맞는지 조사 • Java monitor는 signal-and-continue 접근 2000 운영체제
Solaris 2에서의 동기화(Synchronization in Solaris 2) 1. 적응성(adaptive) mutexes : 짧은 임계구역에 i) multiprocessor system에서 • 처음에는 표준 세마포어처럼 동작(spinlock)하다 사용하려는 데이터가 lock 되었을 때 ① lock한 프로세스가 running thread이면 • 그대로 spinlock 하다가 진행 ② lock한 프로세스가 running thread 아니면(spinlock시간이 길어짐) • sleeping thread로 처리 : block되어 sleep했다가 wakeup됨(바쁜 대기 없는 세마포어 처럼) ii) uniprocessor system에서 • 항상 sleeping thread로 처리 • 다른 thread가 lock test하는 순간 이미 CPU는 다른 thread 처리 중이므로 2. 조건 변수(Condition variable) : 긴 임계구역에 • lock 되었으면 thread는 wait and sleeps • lock을 푸는 스레드가 signal 3. 판독자-기록자 잠금(readers-writers locks) : 긴 임계구역에 • 대부분의 경우 read-only인 data 보호 • semaphore보다 유리 (multiple reads 가능하므로) 2000 운영체제
Windows NT Synchronization • Windows NT Provides: • mutex(뮤텍스) • 스레드가 공유 데이터 접근 위해 사용 • critical sections(임계구역) • 같은 프로세스의 스레드 사이의 동기화 를 제공하는데 사용 • semaphores(세마포어) • event objects(사건 객체) • 조건 변수와 유사한 동기화 객체 • 원하는 조건이 일어났을 때 하나의 대기 스레드에게 통보(notify) 2000 운영체제
수업류시화 엮은 잠언시집 : 지금 알고 있는 걸 그때도 알았더라면 중에서 그때 예수께서 제자들을 산으로 데리고 올라가 곁에 둘러앉히시고 이렇게 가르치셨다. 마음이 가난한 사람은 행복하다. 하늘나라가 그들의 것이다. 온유한 사람은 행복하다. 슬퍼하는 사람은 행복하다. 자비를 베푸는 사람은 행복하다. 박해받는 사람은 행복하다. 고통받는 사람은 행복하다. 하늘나라에서의 보상이 크니 기뻐하고 즐거워하라. 그러자 시몬 베드로가 말했다. “그 말씀을 글로 적어 놓으리까?” 그리고 안드레아가 말했다. “그 말씀을 잘 새겨 둬야 할까요?” 그러자 야고보가 말했다. “그걸 갖고 우리끼리 시험을 쳐볼까요? 그러자 빌립보가 말했다. “우리가 그 뜻을 잘 모를 경우에는 어떻게 할까요?” 그리고 바돌로메가 말했다. “우리가 이 말씀을 다른 사람들에게 전해 줘야 할까요?” 그러자 요한이 말했다. “다른 제자들한테는 이런 걸 알려줄 필요가 있을까요?” 그러자 마태오가 말했다. “우리는 여기서 언제 떠날 건가요?” 그리고 유다가 말했다. “그 말씀이 실생활과는 어떤 관계가 있는 걸까요?” 그리고 그 자리에 참석했던 바리새인 하나는 예수에게 수업 계획서를 보여 줄 것을 요청하면서 그 가르침의 최종적인 목표가 무엇이냐고 물었다. 그러자 예수께서는 우셨다. 작자 미상 M. 스콧 펙 제공 2000 운영체제