동시 스레드 Lock and Condition

Lock and Condition
 
Lock은 기존 스레드 모델의 synchronized 방식보다 대상을 대상으로 하고 생활 속의 자물쇠와 유사하며 자물쇠 자체도 하나의 대상이 되어야 한다.두 스레드가 실행하는 코드 세그먼트를 동기화하려면 같은 Lock 객체를 사용해야 합니다.
l 읽기 자물쇠: 읽기 자물쇠와 쓰기 자물쇠로 나뉘는데 여러 개의 읽기 자물쇠가 서로 배제되지 않는다. 읽기 자물쇠와 쓰기 자물쇠는 서로 배제된다. 이것은 jvm가 스스로 제어하는 것이다. 너는 상응하는 자물쇠만 잘 채우면 된다.만약 당신의 코드가 데이터만 읽는다면 많은 사람들이 동시에 읽을 수 있지만 동시에 쓸 수 없다면 읽기 자물쇠에 올라가세요.만약 코드 수정 데이터가 한 사람만 쓸 수 있고 동시에 읽을 수 없다면 자물쇠를 써라.어쨌든 읽을 때는 자물쇠, 쓸 때는 자물쇠!
l Condition을 기다릴 때'거짓 깨우기'가 발생하는 것을 허용하는데 이것은 보통 기초 플랫폼의 의미에 대한 양보로 한다.대부분의 응용 프로그램에서 이러한 실제 영향은 매우 작다. 왜냐하면 Condition은 항상 하나의 순환에서 기다리고 있는 상태 설명을 테스트해야 하기 때문이다.어떤 실현은 가능한 허위 깨우침을 마음대로 제거할 수 있지만, 프로그램 프로그래머는 항상 이러한 허위 깨우침이 발생할 수 있다고 가정하기 때문에 항상 하나의 순환 속에서 기다릴 것을 권장한다.
l 자물쇠 내부에 여러 개의 Condition이 있을 수 있다. 즉, 다중 대기와 알림이 있을 수 있다. jdk1.5 제공된 Lock과 Condition이 구현한 차단 가능한 대기열의 응용 사례는 알고리즘을 체득해야 할 뿐만 아니라 대상을 대상으로 하는 봉인도 체득해야 한다.전통적인 스레드 메커니즘에서 하나의 모니터 대상에는 하나의 대기와 알림만 있을 수 있다. 다중 대기와 알림을 실현하려면 여러 개의 동기화 모니터 대상을 끼워 넣어야 한다.(한 개의 Condition만 사용하면 두 개가 기다리고 있는데, 한 개가 들어가면 다른 한 개가 아래로 내려갈 수 있음을 알린다.)
 
읽기/쓰기 자물쇠가 있는 이유:
읽기 효율성 향상, 여러 읽기 가능읽을 때 쓰기 동작을 할 수 없습니다.,읽을 때는 다른 읽기 조작이 있을 수 있습니다.
 
잠금의 예 ----------------------------------------------
package thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
public static void main(String[] args) {
final Business business = new Business();
ExecutorService executor =  Executors.newFixedThreadPool(3);
for(int i=0;i<3;i++)
{
executor.execute(
new Runnable()
{
public void run()
{
business.service();
}
}
);
}
executor.shutdown();
}
private static class Business
{
private int count;
Lock lock = new ReentrantLock();
public void service()
{
lock.lock();
try {
count++;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
} catch (RuntimeException e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
} 
}

-------------------읽기/쓰기 자물쇠의 예-------------------------------
주의: 처음에 eclipse for jee 자신의 jdk를 사용했는데 읽기 자물쇠가 병발할 수 있는 효과를 보지 못했는데 나중에 선의 jdk로 바꾸면 효과를 볼 수 있습니다!
 
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockTest {
public static void main(String[] args) {
final Queue3 q3 = new Queue3();
for(int i=0;i<3;i++)
{
new Thread(){
public void run(){
while(true){
q3.get();  
}
}
}.start();
}
for(int i=0;i<3;i++)
{ 
new Thread(){
public void run(){
while(true){
q3.put(new Random().nextInt(10000));
}
} 
}.start(); 
}
}
}
class Queue3{
private Object data = null;// , , 。
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
public void get(){
rwl.readLock().lock();
System.out.println(Thread.currentThread().getName() + " be ready to read data!");
try {
Thread.sleep((long)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + “have read data :“ + data);
rwl.readLock().unlock();
}
public void put(Object data){
rwl.writeLock().lock();
System.out.println(Thread.currentThread().getName() + " be ready to write data!"); 
try {
Thread.sleep((long)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = data; 
System.out.println(Thread.currentThread().getName() + " have write data: “ + data);
rwl.writeLock().unlock(); 
}
}

------------------Condition의 예1: 두 스레드의 교체 실행을 실현-----------------------------------------
public class ConditionTest {
public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
final Business2 business = new Business2();
service.execute(new Runnable(){
public void run() {
for(int i=0;i<50;i++){
business.sub();
}
}
});
for(int i=0;i<50;i++){
business.main();
}
}
}
class Business2{
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
boolean bShouldSub = true;
public void sub(){
lock.lock();
if(!bShouldSub)
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
try
{
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName() + " : " + i);
}
bShouldSub = false;
condition.signal();
}finally{
lock.unlock();
}
}
public void main(){
lock.lock();
if(bShouldSub)
try {
condition.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} 
try
{
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName() + " : " + i);
}
bShouldSub = true;
condition.signal(); 
}finally{
lock.unlock();
} 
}
}

---------Condition의 예2: 세 스레드의 교체 운행을 실현하는 효과 --------------------------
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SignalTest2 {
public static void main(String[] args) {
new SignalTest2().init();
}
private void init(){
final Business b = new Business();
new Thread(){
public void run(){
for(int i=0;i<50;i++)
b.main();
}
}.start();
new Thread(){
public void run(){
for(int i=0;i<50;i++)  
b.sub();
} 
}.start();
new Thread(){
public void run(){
for(int i=0;i<50;i++)  
b.sub2();
} 
}.start(); 
}
private class Business{
int status = 1;
Lock lock = new ReentrantLock();
Condition cond1 = lock.newCondition();
Condition cond2 = lock.newCondition();
Condition cond3 = lock.newCondition(); 
public  void main(){
lock.lock();
while(status != 1){
try{cond1.await();}catch(Exception e){}
}
for(int i=1;i<=5;i++){
  try{Thread.sleep(200);}catch(Exception e){}
  System.out.println(Thread.currentThread().getName() + ":" + i);
}
status = 2;
cond2.signal();
lock.unlock();
}
public  void sub(){
lock.lock(); 
while(status != 2){
try{cond2.await();}catch(Exception e){}
}
for(int i=1;i<=10;i++){
  try{Thread.sleep(200);}catch(Exception e){}
  System.out.println(Thread.currentThread().getName() + ":" + i);
}
status = 3;
cond3.signal();
lock.unlock();
}
public  void sub2(){
lock.lock(); 
while(status != 3){
try{cond3.await();}catch(Exception e){}
}
for(int i=1;i<=10;i++){
  try{Thread.sleep(200);}catch(Exception e){}
  System.out.println(Thread.currentThread().getName() + ":" + i);
}
status = 1;
cond1.signal();
lock.unlock();
} 
}
}

 
Semaphore
Semaphore는 현재 자신에게 접근하는 스레드 수를 유지하고 동기화 메커니즘을 제공합니다.Semaphore를 사용하면 한 파일이 허용하는 병렬 접근 수를 제어할 수 있습니다.
단일 신호량의 Semaphore 대상은 서로 자물쇠를 배제하는 기능을 실현할 수 있고 한 라인에서'자물쇠'를 얻은 다음에 다른 라인에서'자물쇠'를 방출할 수 있다. 이것은 자물쇠가 사라지는 일부 장소에 응용할 수 있다.
 
package cn.itcast.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreTest {
 public static void main(String[] args) {
  ExecutorService service = Executors.newCachedThreadPool();
  final  Semaphore sp = new Semaphore(3);
  for(int i=0;i<10;i++){
   Runnable runnable = new Runnable(){
     public void run(){
     try {
      sp.acquire();
     } catch (InterruptedException e1) {
      e1.printStackTrace();
     }
     System.out.println(" " + Thread.currentThread().getName() + 
       " , " + (3-sp.availablePermits()) + " ");
     try {
      Thread.sleep((long)(Math.random()*10000));
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
     System.out.println(" " + Thread.currentThread().getName() + 
       " ");     
     sp.release();
     // , 
     System.out.println(" " + Thread.currentThread().getName() + 
       " , " + (3-sp.availablePermits()) + " ");     
    }
   };
   service.execute(runnable);   
  }

 }

}

 
CyclicBarrier
⑥ 서로 기다린다는 의미로, 모두 집합이 끝난 후에야 출발하고, 분산 활동을 한 후에 또 지정된 장소에서 집합하여 만난다는 의미로, 회사 전체의 인원이 주말 시간을 이용하여 단체로 소풍을 가는 것과 같이 먼저 각자 집에서 회사로 집합한 후, 동시에 공원으로 소풍을 가고, 지정된 장소에서 집합한 후에 동시에 식사를 시작하는 것과 같다.
lCountDownLatch
⑥ 카운터처럼 CountDownLatch 객체의 countDown 방법을 호출하면 카운터를 1로 줄이고 카운터가 0에 도달하면 모든 대기자나 한 대기자가 실행을 시작합니다.이것은 코드를 통해 CountDownLatch의 작용을 직접 설명함으로써 학생들의 이해 효과가 더욱 직접적이다.
⑥ 한 사람(또는 여러 사람)이 다른 모든 사람이 그에게 통지할 때까지 기다릴 수 있다. 이것은 하나의 계획이 여러 명의 지도자가 서명해야만 계속 아래로 실시할 수 있는 것과 같다.한 사람이 여러 사람에게 알리는 효과도 실현할 수 있다. 마치 심판의 구령과 같이 운동선수가 동시에 달리기 시작한다.이 기능으로 100미터 달리기 게임 프로그램을 만들면 괜찮다!
lExchanger
⑥ 특정 트랜잭션을 수행한 후 서로 데이터를 교환하고자 하는 두 사람 간의 데이터 교환을 위해 사용되며, 첫 번째로 데이터를 먼저 꺼낸 사람은 두 번째 사람이 데이터를 가져올 때까지 기다려야 서로 데이터를 교환할 수 있습니다.
 
 
-------------CyclicBarrier의 코드:-----------------------------------------------
package cn.itcast.day3.thread;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class CyclicBarrierTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final  CyclicBarrier cb = new CyclicBarrier(3);
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
  Thread.sleep((long)(Math.random()*10000)); 
System.out.println(" " + Thread.currentThread().getName() + 
" 1, " + cb.getNumberWaiting() + " , ");  
cb.await();
  Thread.sleep((long)(Math.random()*10000)); 
System.out.println(" " + Thread.currentThread().getName() + 
" 2, " + cb.getNumberWaiting() + " , ");  
cb.await(); 
  Thread.sleep((long)(Math.random()*10000)); 
System.out.println(" " + Thread.currentThread().getName() + 
" 3, " + cb.getNumberWaiting() + " , ");  
cb.await();  
} catch (Exception e) {
e.printStackTrace();
}  
}
};
service.execute(runnable);
}
service.shutdown();
}
}

-------------CountdownLatch 코드:-----------------------------------------------
 
package cn.itcast.day3.thread;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountdownLatchTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);
final CountDownLatch cdAnswer = new CountDownLatch(3); 
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
System.out.println(" " + Thread.currentThread().getName() + 
" "); 
cdOrder.await();
System.out.println(" " + Thread.currentThread().getName() + 
" ");  
  Thread.sleep((long)(Math.random()*10000)); 
System.out.println(" " + Thread.currentThread().getName() + 
" "); 
cdAnswer.countDown();  
} catch (Exception e) {
e.printStackTrace();
}  
}
};
service.execute(runnable);
} 
try {
Thread.sleep((long)(Math.random()*10000));
System.out.println(" " + Thread.currentThread().getName() + 
" ");  
cdOrder.countDown();
System.out.println(" " + Thread.currentThread().getName() + 
" , "); 
cdAnswer.await();
System.out.println(" " + Thread.currentThread().getName() + 
" "); 
} catch (Exception e) {
e.printStackTrace();
} 
service.shutdown();
}
}

---------------------------ExchangerTest-------------------------
Exchanger의 비유를 설명하자면 두 명의 마약 판매상이 거래를 하고 한 손으로는 돈을 내고 한 손으로는 물건을 인도하는 것과 같다. 누가 먼저 접선 지점에 도착한 후에 대기 상태에 있다. 다른 한 쪽도 접선 지점에 도착했을 때(이른바 접선 지점, 즉 접선 준비 상태에 도달했을 때) 두 사람의 데이터는 즉시 교환되고 그 다음에 각자 바쁠 수 있다.
exchange 방법은 두 손을 높이 들고 교환물을 기다리며 교환을 기다리는 것과 같다. 일단 사람이 오면 (즉 다른 사람도 exchange 방법을 집행한다) 둘은 바로 데이터의 교환을 완성한다.
 
package cn.itcast.day3.thread;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExchangerTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Exchanger exchanger = new Exchanger();
service.execute(new Runnable(){
public void run() {
try { 
Thread.sleep((long)(Math.random()*10000));
String data1 = "zxx";
System.out.println(" " + Thread.currentThread().getName() + 
" " + data1 +" ");
String data2 = (String)exchanger.exchange(data1);
System.out.println(" " + Thread.currentThread().getName() + 
" " + data2);
}catch(Exception e){
}
} 
});
service.execute(new Runnable(){
public void run() {
try { 
Thread.sleep((long)(Math.random()*10000));
String data1 = "lhm";
System.out.println(" " + Thread.currentThread().getName() + 
" " + data1 +" ");
String data2 = (String)exchanger.exchange(data1);
System.out.println(" " + Thread.currentThread().getName() + 
" " + data2);
}catch(Exception e){
} 
} 
}); 
}
}

 
Java5에는 다음과 같은 동기화 클래스가 있습니다.
⑥ java를 참조하십시오.util.concurrent 패키지 아래의 소개는 어떤 병렬 집합이 있는지 알 수 있습니다
ØConcurrentHashMap
ØCopyOnWriteArrayList
ØCopyOnWriteArraySet
 
 
 
 
 
 
 
 

좋은 웹페이지 즐겨찾기