멀티쓰레드 프로그래밍
임계영역(critical section)
- 두 개 이상의 thread가 동시에 접근하게 되는 리소스
- critical section에 동시에 thread가 접근하게 되면 실행 결과를 보장 할 수 없음
- thread간의 순서를 맞추는 동기화(synchronized)이 필요
동기화(synchronized)
- 임계 영역에 여러 thread가 접근하는 경우 한 thread가 수행 하는 동안 공유 자원을 lock하려
다른 thread의 접근을 막음
- 동기화를 잘못 구현하면 deadlock에 빠질 수 있음
자바에서 동기화 구현
- synchronized수행문과 synchronized 메서드를 이용
1. synchronized 수행문
synchronized(참조형 수식){
}
참조형 수식에 해당되는 개체에 lock을 건다.
2. synchronized 메서드
- 현재 이 메서드가 속해 있는 객체에 lock를 건다.
sychronized메서드 내에서 다른 synchronized 메서드를 호출하지 않는다.(deadlock 방지를 위해)
문제 발생시점
- static를 가지고 있는 변수들의 자원들을 공유하면서 멀티쓰레드에 관련된 문제가 발생 될 수 있다.
package thread;
class Bank {
private int mony = 10000;
public void saveMoney(int save) {
int m = this.getMony();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setMony(m+save);
}
public void minusMoney(int minus) {
int m = this.getMony();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setMony(m-minus);
}
int getMony() {
return mony;
}
private void setMony(int mony) {
this.mony = mony;
}
}
class Park extends Thread{
public void run() {
System.out.println("Start Save");
SyncTest.myBank.saveMoney(3000);
System.out.println("Start End"+"savemoney"+SyncTest.myBank.getMony());
}
}
class ParkWife extends Thread{
public void run() {
System.out.println("Start minus");
SyncTest.myBank.minusMoney(1000);
System.out.println("Start End"+"minusmoney"+SyncTest.myBank.getMony());
}
}
public class SyncTest {
public static Bank myBank = new Bank();
public static void main(String[] args) throws InterruptedException {
Park p = new Park();
p.start();
Thread.sleep(200);
ParkWife pw = new ParkWife();
pw.start();
}
}
위의 코드는 동기화가 안되어 나온 결과 값
Start Save
Start minus
Start Endminusmoney9000
Start Endsavemoney13000
동기화가 적용된 코드
package thread;
class Bank {
private int mony = 10000;
public synchronized void saveMoney(int save) {
int m = this.getMony();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setMony(m+save);
}
public synchronized void minusMoney(int minus) {
int m = this.getMony();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setMony(m-minus);
}
int getMony() {
return mony;
}
private void setMony(int mony) {
this.mony = mony;
}
}
class Park extends Thread{
public void run() {
System.out.println("Start Save");
SyncTest.myBank.saveMoney(3000);
System.out.println("Start End"+"savemoney"+SyncTest.myBank.getMony());
}
}
class ParkWife extends Thread{
public void run() {
System.out.println("Start minus");
SyncTest.myBank.minusMoney(1000);
System.out.println("Start End"+"minusmoney"+SyncTest.myBank.getMony());
}
}
public class SyncTest {
public static Bank myBank = new Bank();
public static void main(String[] args) throws InterruptedException {
Park p = new Park();
p.start();
Thread.sleep(200);
ParkWife pw = new ParkWife();
pw.start();
}
}
위의 코드는 동기화가 적용되어 나온 결과 값
Start Save
Start minus
Start Endsavemoney13000
Start Endminusmoney12000
Synchronized 수행문을 적용한 것과 synchronized 메서드를 적용한 수행문
package thread;
class Bank {
private int mony = 10000;
public void saveMoney(int save) {
synchronized(this) {
int m = this.getMony();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setMony(m+save);
}
}
public synchronized void minusMoney(int minus) {
int m = this.getMony();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setMony(m-minus);
}
int getMony() {
return mony;
}
private void setMony(int mony) {
this.mony = mony;
}
}
class Park extends Thread{
public void run() {
System.out.println("Start Save");
SyncTest.myBank.saveMoney(3000);
System.out.println("Start End"+"savemoney"+SyncTest.myBank.getMony());
}
}
class ParkWife extends Thread{
public void run() {
System.out.println("Start minus");
SyncTest.myBank.minusMoney(1000);
System.out.println("Start End"+"minusmoney"+SyncTest.myBank.getMony());
}
}
public class SyncTest {
public static Bank myBank = new Bank();
public static void main(String[] args) throws InterruptedException {
Park p = new Park();
p.start();
Thread.sleep(200);
ParkWife pw = new ParkWife();
pw.start();
}
}
run() 부분에 lock을 걸어봤자 소용이 없다.
쓰레드 부분에 락을 건 것이 아니기 떄문에 소용이 없다.
- public synchronized void run(){
}
이 부분에 락을 걸고 싶을 경우에는 블락 방식으로 적용시켜주면 가능하다.
-
public void run(){
synchronized(SyncTest.myBank){
코드
}
}
'JAVA' 카테고리의 다른 글
Chapter01. 변수 (0) | 2023.02.23 |
---|---|
멀티쓰레드 프로그래밍 multi-thread programming (0) | 2019.10.29 |
Thread status ( 쓰레드 상태 ) -활용 (0) | 2019.10.27 |
Thread class (0) | 2019.10.26 |
입출력 클래스 및 데코레이터패턴 (0) | 2019.10.25 |