자바(SE)

Thread의 join 사용 예

  • -

다음의 무거운 작업을 수행해야한다고 생각해보자.

public long heavyWork(int th) {
	long result = 1;
	for (int i = 0; i < Integer.MAX_VALUE; i++) {
		result += i;
	}
	System.out.printf("%d th done: %d\n", th, result);
	return result;
}

위의 작업을 총 10번 해서 총 결과를 알고 싶다면 아래와 같이 작업할 수 있다.

public void getSumByNormal() {
	long first = System.currentTimeMillis();
	long result = 0;
	for (int i = 0; i < 10; i++) {
		result += heavyWork(i);
	}
	long second = System.currentTimeMillis();
	System.out.printf("normal: >> 소요시간: %d, 결과: %d\n", (second - first), result);
}

위의 작업은 절차적으로 진행되므로 출력되는 로그는 아래와 같다. (값은 overflow가 발생한다.)

0 th done: 2305843005992468482
1 th done: 2305843005992468482
2 th done: 2305843005992468482
3 th done: 2305843005992468482
4 th done: 2305843005992468482
5 th done: 2305843005992468482
6 th done: 2305843005992468482
7 th done: 2305843005992468482
8 th done: 2305843005992468482
9 th done: 2305843005992468482
normal: >> 소요시간: 5894, 결과: 4611685986215133204

무거운 작업은 별도의 스레드로 분리해서 작업하면 효율을 높일 수 있다. 

Long d1 = 0L;

class SumThread extends Thread {
	int th = 0;
	public SumThread(int th) {
		this.th = th;
	}

	@Override
	public void run() {
		d1+=heavyWork(th);
	}
}

d1은 여러 스레드가 작업 결과를 저장할 공유 자원이다.

 

위 스레드를 이용해서 동시에 10개의 덧샘을 실행 후 결과를 다시 합해보자. 이때 주의할 점은 계산하는 스레드들이 모두 종료하기 전에는 main이 종료하면 안된다. 이를 위해 join() 메서드를 사용할 수 있다.

public void getSumByThread() throws InterruptedException {
	long first = System.currentTimeMillis();
	List<SumThread> threads = new ArrayList<>();
	for (int i = 0; i < 10; i++) {
		SumThread st = new SumThread(i);
		threads.add(st);
		st.start();
	}
	for (Thread t : threads) {	// 각 스레드의 작업이 끝날 때까지 main 메서드의 작업은 종료되어야 한다.
		t.join();
	}
	long second = System.currentTimeMillis();
	System.out.printf("normal: >> 소요시간: %d, 결과: %d\n", (second - first), d1);
}

이제 스레드들은 비 순차적으로 작업을 완료되고 작업에 소요된 시간이 대폭 줄어든 것을 볼 수 있다. 

3 th done: 2305843005992468482
7 th done: 2305843005992468482
6 th done: 2305843005992468482
1 th done: 2305843005992468482
0 th done: 2305843005992468482
4 th done: 2305843005992468482
2 th done: 2305843005992468482
8 th done: 2305843005992468482
9 th done: 2305843005992468482
5 th done: 2305843005992468482
normal: >> 소요시간: 883, 결과: 2305843005992468482

하지만 작업의 결과는 원래의 결과와 다름을 알 수 있다.

공유자원인 d1에 여러 스레드가 동시에 접근해서 값을 바꾸는 과정에서 문제가 발생한 것이다.

 

스레드들의 공유자원 접근 문제를 해결하기 위해 synchronized 키워드를 이용해서 동기화 처리가 필요하다.

class SumThread extends Thread {
	int th = 0;

	public SumThread(int th) {
		this.th = th;
	}

	@Override
	public void run() {
		//d1+=heavyWork(th);
		add(heavyWork(th));
	}
}

public synchronized void add(long unitSum) {
	d1 += unitSum;
}

동기화 처리 후 작업 결과를 보면 정확한 합계를 확인할 수 있다.

2 th done: 2305843005992468482
9 th done: 2305843005992468482
6 th done: 2305843005992468482
5 th done: 2305843005992468482
3 th done: 2305843005992468482
1 th done: 2305843005992468482
4 th done: 2305843005992468482
7 th done: 2305843005992468482
8 th done: 2305843005992468482
0 th done: 2305843005992468482
normal: >> 소요시간: 850, 결과: 4611685986215133204

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.