Please Enable JavaScript!
Gon[ Enable JavaScript ]

[Java] 자바 동기화(synchronezed) 하는 방법

자바(JAVA)

[Java] 자바 동기화(synchronezed) 하는 방법

 

환경 : Eclipse Mars, Android 4.2.2

 

자바에서 동기화란 여러 개의 스레드가 한 개의 자원을 사용하고자 할 때 해당 스레드만 제외하고 나머지는 접근을 못하도록 막는 것입니다. 자바 동기화는 synchronized 식별자로 구현하게 됩니다. 변수와 함수에 사용해서 동기화 할수 있습니다. 파워풀한 기능을 간단하게 사용할수 있다는 장점이 있지만 남발하면 안됩니다. 성능상에 문제를 줄수 있기 때문입니다.

 

▼ 아래 소스 처럼 synchronized 식별자는 함수와 변수에 사용이 가능합니다. 변수에 사용할때는 블록을 지정하시고 그안에 코드를 넣습니다. 이렇게 스레드를 처리해야 되는 경우는 하나의 객체에 여러 스레드가 접근해서 처리할 때 입니다.

 

// 1. 함수에 사용하는 경우
public synchronized void method() {
	 //code
}

// 2. 객체 변수에 사용하는 경우
private Object obj = new Object();
public void exampleMethod() {
	synchronized(obj) {
		//code
	}
}

 

▼ 아래 샘플은 3개의 스레드가 돌아가면서 User 클래스에 있는 Add 함수를 호출하는 과정입니다. add() 함수를 동기화하지 않고 그대로 두게 되면 출력값이 차례대로 되지 않고 바뀌는 경우가 생깁니다. 예를 들어 B2 스레드가 번호를 4로 증가하고 출력할려고 하는데 C3 스레드가 방금 증가한 4에 하나를 더해서 먼저 5를 출력한 것입니다. 그래서 아래 결과값에 B2, C3 가 뒤바뀐 것입니다.

class User {
	private int userNo = 0;

	// 임계 영역을 지정하는 synchronized메소드
	public void add(String name) {
		System.out.println(name + " : " + userNo++ + "번째 사용");
	}
}

class UserThread extends Thread {
	User user;

	UserThread(User user, String name) {
		super(name);
		this.user = user;
	}

	public void run() {
		try {
			for (int i = 0; i < 3; i++) {
				user.add(getName());
				sleep(500);
			}
		} catch (InterruptedException e) {
			System.err.println(e.getMessage());
		}
	}
}

public class SyncThread {

	public static void main(String[] args) {

		User user = new User();

		// 3개의 스레드 객체 생성
		UserThread p1 = new UserThread(user, "A1");
		UserThread p2 = new UserThread(user, "B2");
		UserThread p3 = new UserThread(user, "C3");

		// 스레드 스케줄링 : 우선순위 부여
		p1.setPriority(p1.MAX_PRIORITY);
		p2.setPriority(p2.NORM_PRIORITY);
		p3.setPriority(p3.MIN_PRIORITY);

		System.out.println("-----------------------");
		System.out.println("sychronized 적용안한 경우");
		System.out.println("-----------------------");

		// 스레드 시작
		p1.start();
		p2.start();
		p3.start();
	}
}
// 결과 
-----------------------
sychronized 적용안한 경우
-----------------------
A1 : 0번째 사용
B2 : 1번째 사용
C3 : 2번째 사용
A1 : 3번째 사용
C3 : 5번째 사용
B2 : 4번째 사용
C3 : 7번째 사용
A1 : 6번째 사용
B2 : 8번째 사용

 

▼ 이렇게 동기화를 하지 않으면 어떤 일이 발생할지 모릅니다. 사용자가 의도한대로 차례대로 출력할려면 출력이 끝날 때 까지 add() 함수로 아무도 못들어오게 막아야 겠죠. 아래 소스는 add() 함수에 synchronized 적용한 것입니다. 번호 증가가 차례대로 되는 것을 알수 있습니다.

class User {
	private int userNo = 0;

	// 임계 영역을 지정하는 synchronized메소드
	public synchronized void add(String name) {
		System.out.println(name + " : " + userNo++ + "번째 사용");
	}
}

class UserThread extends Thread {
	User user;

	UserThread(User user, String name) {
		super(name);
		this.user = user;
	}

	public void run() {
		try {
			for (int i = 0; i < 3; i++) {
				user.add(getName());
				sleep(500);
			}
		} catch (InterruptedException e) {
			System.err.println(e.getMessage());
		}
	}
}

public class SyncThread {

	public static void main(String[] args) {

		User user = new User();

		// 3개의 스레드 객체 생성
		UserThread p1 = new UserThread(user, "A1");
		UserThread p2 = new UserThread(user, "B2");
		UserThread p3 = new UserThread(user, "C3");

		// 스레드 스케줄링 : 우선순위 부여
		p1.setPriority(p1.MAX_PRIORITY);
		p2.setPriority(p2.NORM_PRIORITY);
		p3.setPriority(p3.MIN_PRIORITY);

		System.out.println("-----------------------");
		System.out.println("sychronized 적용안한 경우");
		System.out.println("-----------------------");

		// 스레드 시작
		p1.start();
		p2.start();
		p3.start();
	}
}
// 결과 
-----------------------
sychronized 적용안한 경우
-----------------------
A1 : 0번째 사용
C3 : 1번째 사용
B2 : 2번째 사용
A1 : 3번째 사용
B2 : 4번째 사용
C3 : 5번째 사용
A1 : 6번째 사용
B2 : 7번째 사용
C3 : 8번째 사용
Posted by 녹두장군

댓글을 달아 주세요

  1. 행인 2016.10.08 15:31  댓글주소  수정/삭제  댓글쓰기

    밑의 예제에 sysout 에서 동기화 적용한 경우로 출력해야 하지 않을까요?

  2. Favicon of https://chemeez.tistory.com 맛 밀 2017.10.12 18:23 신고  댓글주소  수정/삭제  댓글쓰기

    감사히 잘 봤습니다^o^

  3. Favicon of http://min9nim.github.io keating 2018.12.21 10:08  댓글주소  수정/삭제  댓글쓰기

    두번째 예제 동기화적용한 경우로 출력 바꿔야 하는데 안 바꿔놓으셨네요..

  4. 사병1 2019.08.02 08:17  댓글주소  수정/삭제  댓글쓰기

    감사합니다 장군!!!