공유
아래와 같은 방식으로 run()에서 공유할 객체에 접근하는 것이 가능해진다.
예) 쓰레드가 객체를 공유하게 되는 방식 1 - Runnable 인터페이스 상속
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import java.util.*; class example { public static void main(String[] args) { RunnableImpl r = new RunnableImpl(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); } } class RunnableImpl implements Runnable { int iv = 0 ; @Override public void run() { int lv = 0 ; String name = Thread.currentThread().getName(); while (lv < 3 ) { System.out.println(name + " Local Var:" + ++lv); System.out.println(name + " Instance Var:" + ++iv); System.out.println(); } } } |
결과)
Thread-0 Local Var:1
Thread-0 Instance Var:1
Thread-0 Local Var:2
Thread-0 Instance Var:2
Thread-0 Local Var:3
Thread-0 Instance Var:3
Thread-1 Local Var:1
Thread-1 Instance Var:4
Thread-1 Local Var:2
Thread-1 Instance Var:5
Thread-1 Local Var:3
Thread-1 Instance Var:6
예) 쓰레드가 객체를 공유하게 되는 방식 2 - Thread 상속
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | import java.util.*; class example { public static void main(String[] args) { Data d = new Data(); MyThread t1 = new MyThread(d); MyThread t2 = new MyThread(d); t1.start(); t2.start(); } } class Data { int iv = 0 ; } class MyThread extends Thread{ Data d; MyThread(Data d) { this .d = d; } @Override public void run() { int lv = 0 ; while (lv < 3 ) { System.out.println(getName() + " Local Var:" + ++lv); System.out.println(getName() + " Instance Var:" + ++d.iv); System.out.println(); } } } |
결과)
Thread-0 Local Var:1
Thread-0 Instance Var:1
Thread-0 Local Var:2
Thread-0 Instance Var:2
Thread-0 Local Var:3
Thread-0 Instance Var:3
Thread-1 Local Var:1
Thread-1 Instance Var:4
Thread-1 Local Var:2
Thread-1 Instance Var:5
Thread-1 Local Var:3
Thread-1 Instance Var:6
동기화(Synchronized)
- 공유 데이터에 lock을 걸어 작업중이던 쓰레드가 마칠때까지 다른 쓰레드에게 제어권이 넘어가지않게 보호한다.
- synchronized 블럭이 끝나면 lock이 풀리고 다른 쓰레드도 접근가능하게 된다.
- 교착상태(dead-lock)에 빠질 위험이 있으므로 주의한다.
synchronized를 이용한 동기화 방법
- 가능하면 메서드에 synchronized를 사용하는 메서드 단위의 동기화를 권장
1 2 3 4 5 6 7 8 9 | 1 . 특정한 객체에 lock을 걸고자 할 때 synchronized (객체의 참조변수){ // ... } 2 . 메서드에 lock을 걸고자할 때 public synchronized void calcSum(){ // ... } |
예) 동기화 적용 전 : if문을 통과하고 출금을 수행하려는 순간 다른 쓰레드에게 제어권이 넘어가서 다른 쓰레드가 출금을 해버렸고(잔고:0) 또 이전의 쓰레드로 제어권이 넘어오면서 출금을 수행했기 때문에 잔고가 음수가 되어버렸다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import java.util.*; class example { public static void main(String[] args) { MyThread r = new MyThread(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); } } class Account{ int balance = 1000 ; public void withDraw( int money){ if (balance >= money){ try { Thread.sleep( 1000 ); } catch (Exception e) {} balance -= money; } } } class MyThread implements Runnable{ Account acc = new Account(); @Override public void run() { while (acc.balance > 0 ){ // 100, 200, 300 중의 한 값을 임의로 선택해서 출금(withDraw) int money = ( int )(Math.random() * 3 + 1 ) * 100 ; acc.withDraw(money); System.out.println( "balance:" + acc.balance); } } } |
결과)
balance:500
balance:500
balance:300
balance:0
balance:-300
예) 동기화 적용 후
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | import java.util.*; class example { public static void main(String[] args) { MyThread r = new MyThread(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); } } class Account{ int balance = 1000 ; // 동기화 적용 (메서드 단위의 동기화를 추천한다.) public synchronized void withDraw( int money){ /* 객체에 lock을 걸 경우 synchronized (this) { 여기에 소스 코드를 집어 넣어도 된다. } */ if (balance >= money){ try { Thread.sleep( 1000 ); } catch (Exception e) {} balance -= money; } } } class MyThread implements Runnable{ Account acc = new Account(); @Override public void run() { while (acc.balance > 0 ){ // 100, 200, 300 중의 한 값을 임의로 선택해서 출금(withDraw) int money = ( int )(Math.random() * 3 + 1 ) * 100 ; acc.withDraw(money); System.out.println( "balance:" + acc.balance); } } } |
결과)
balance:700
balance:700
balance:500
balance:400
balance:200
balance:0
balance:0
Lock Flag : 자바 객체마다 한개씩 있는 키. 인스턴스 메소드마다 존재하는 키가 하나씩 있음.
Lock Pool : Lock된 코드를 만난 쓰레드가 대기하는 장소
'Programming > Java' 카테고리의 다른 글
[swing] Event Dispatch Thread (0) | 2016.02.04 |
---|---|
serializable (0) | 2016.01.29 |
vector (0) | 2016.01.22 |
String (0) | 2016.01.21 |
equals, hashcode (0) | 2016.01.21 |