본문 바로가기
Java/Java

[Java] 쓰레드(Thread) 동기화

by 기록하는_사람 2022. 10. 24.

쓰레드(Thread) 동기화

📌 쓰레드(Thread) 동기화

: 둘 이상의 쓰레드가  동일한 메모리 공간에 접근할때 문제가 생기는 것을 막기 위해 사용. 

 

📄 ThreadSynchronizationTest.java

package threadSynchronization;

class Counter {
	int count = 0;
	
	public void increment() { count++; }
	public void decrement() { count--; }
	public int getCount() { return count; }
}

public class ThreadSynchronizationTest {
	public static Counter cnt = new Counter();

	public static void main(String[] args) throws InterruptedException {
		Runnable task1 = () -> {
			for(int i = 0; i < 1000; i++) { cnt.increment(); }
		};

		Runnable task2 = () -> {
			for(int i = 0; i < 1000; i++) { cnt.decrement(); }
		};
		
		Thread t1 = new Thread(task1);
		Thread t2 = new Thread(task2);
		
		t1.start();
		t2.start();
		
		t1.join();
		t2.join();
		
		System.out.println(cnt.getCount());
	}

}

// 실행할 때마다 출력되는 값이 다름.

 

쓰레드(Thread) 동기화 방법 - 동기화(Synchronization) 메소드

📌 동기화(Synchronization) 메소드

: 두 쓰레드가 동시에 호출할 경우, 좀 더 빨리 호출한 쓰레드가 메소드를 실행하고, 다른 쓰레드는 대기하다가 먼저 호출한 쓰레드가 실행을 마치면 메소드를 실행하도록 함. 

synchronized public void increment() {
	count++
}

 

📌 한 클래스의 두 메소드에 synchronized를 선언하면, 두 메소드는 둘 이상의 쓰레드에 의해 동시에 실행될 수 없도록 동기화됨. 

 

📄 ThreadSynchronizationTest2.java

package threadSynchronization2;

class Counter {
	int count = 0;
	
	synchronized public void increment() { count++; }
	synchronized public void decrement() { count--; }
	public int getCount() { return count; }
}

public class ThreadSynchronizationTest2 {
	public static Counter cnt = new Counter();

	public static void main(String[] args) throws InterruptedException {
		Runnable task1 = () -> {
			for(int i = 0; i < 1000; i++) { cnt.increment(); }
		};

		Runnable task2 = () -> {
			for(int i = 0; i < 1000; i++) { cnt.decrement(); }
		};
		
		Thread t1 = new Thread(task1);
		Thread t2 = new Thread(task2);
		
		t1.start();
		t2.start();
		
		t1.join();
		t2.join();
		
		System.out.println(cnt.getCount());  // 0
	}
}

 

쓰레드(Thread) 동기화 방법 - 동기화(Synchronization) 블록

📌 동기화(Synchronization) 블록

: 문장 단위로 동기화.

 

📄 ThreadSynchronizationTest3.java

package threadSynchronization3;

class Counter {
	int count = 0;
	
	public void increment() { 
		synchronized(this) { count++; }
	}
	public void decrement() { 
		synchronized(this) { count--; }
	}
	public int getCount() { return count; }
}

public class ThreadSynchronizationTest3 {
	public static Counter cnt = new Counter();

	public static void main(String[] args) throws InterruptedException {
		Runnable task1 = () -> {
			for(int i = 0; i < 1000; i++) { cnt.increment(); }
		};

		Runnable task2 = () -> {
			for(int i = 0; i < 1000; i++) { cnt.decrement(); }
		};
		
		Thread t1 = new Thread(task1);
		Thread t2 = new Thread(task2);
		
		t1.start();
		t2.start();
		
		t1.join();
		t2.join();
		
		System.out.println(cnt.getCount());  // 0
	}
}

 

쓰레드(Thread) 동기화 방법 - ReentrantLock 클래스

📌 ReentrantLock 클래스

class Test {
	ReentrantLock r = new ReentrantLock();

	void testMethod(int arg) {
		r.lock();
		...
		r.unlock();
	}
}
class Test {
	ReentrantLock r = new ReentrantLock();

	void testMethod(int arg) {
		r.lock();

		try {
			...  // 한 쓰레드에 의해 실행되는 영역. 
		}
		finally {
			r.unlock(); 
		}
	}
}

 

쓰레드 풀(Thread Pool)

📌 쓰레드 풀(Thread Pool)

: 안에 미리 제한된 수의 쓰레드를 생성해 두고 재활용해 사용는 기술.

  java.util.concurrent 패키지. 

 

📌 쓰레드 풀(Thread Pool) 생성 방법

newSingleThreadExecutor - 풀 안에 하나의 쓰레드만 생성하고 유지함. 
- 단점 : 마지막에 전달된 작업은 가장 늦게 처리됨. 
newFixedThreadPool - 풀 안에 인자로 전달된 수의 쓰레드를 생성하고 유지함.
newCachedThreadPool - 풀 안에 쓰레드의 수를 작업 수에 맞게 유동적으로 관리함. 
- 단점 : 빈번한 쓰레드 생성과 소멸이 이뤄질 수 있음. 

 

📄 ThreadPoolTest.java

package threadPool;

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

public class ThreadPoolTest {

	public static void main(String[] args) {
		Runnable task = () -> {
			int n1 = 10;
			int n2 = 20;
			
			String name = Thread.currentThread().getName();
			System.out.println(name + " : " + n1 + " " + n2);
		};
		
		ExecutorService e = Executors.newSingleThreadExecutor();  // 쓰레드 풀 생성. 
		e.submit(task);  // 작업 전달. 
		
		System.out.println("End : " + Thread.currentThread().getName());
		e.shutdown();
	}

}

// End : main
// pool-1-thread-1 : 10 20

+ 추가 설명

더보기

- ExecutorService e = Executors.newSingleThreadExecutor(); \

  → 쓰레드 풀 생성.


- e.submit(task);  

  → 작업 전달.

      풀에서 대기하던 쓰레드가 일을 실행하고, 일이 끝나면 다시 풀로 돌아가 기다림. 

 

- e.shutdown();

  → 생성된 풀과 그 안에 존재하는 쓰레드 소멸. 

 

'Java > Java' 카테고리의 다른 글

[Java] 쓰레드(Thread)  (0) 2022.10.24
[Java] I/O 스트림  (0) 2022.10.22
[Java] 예외 처리  (0) 2022.10.22
[Java] 최종 연산  (0) 2022.10.21
[Java] 중간 연산 - 정렬과 루핑(Looping)  (0) 2022.10.21

댓글