Day 81, 82

dokiru·2023년 5월 23일
0

학원

목록 보기
43/51

스레드 우선순위

  1. 동시성 : 멀티 작업을 위해 하나의 코어에서 멀티 스레드가 번갈아가며 실행하는 성질

  2. 병렬성 : 멀티 작업을 위해 멀티 코어에서 개별 스레드를 동시에 실행하는 성질

스레드 충돌

  1. 각각의 객체 but 하나의 객체를 공유해서 작업
  2. 어차피 하나의 객체를 스레드가 나눠서 실행된다

동기화 (synchronized)

  • 멀티 스레드에서 스레드들이 객체를 공유해서 작업해야하는 경우 발생
  • 스레드가 객체 내부의 동기화 메소드 또는 블록에 들어가면 즉시 객체에 잠금을 걸어 다른 스레드가 접근하지 못하도록 함
  • synchronized 키워드는 인스턴스와 정적 메소드 어디든 붙일 수 있음
  • 메소드를 부르는 곳에서 synchronized 키워드를 붙여주거나 메소드를 정의할 때에 붙여준다
public void method() {
	//여러 스레드가 실행 가능한 영역
    ...
    synchronized(공유객체) { // 공유 객체가 객체 자신이면 this를 넣을 수 있음
    	임계 영역 //단 하나의 스레드만 실행
    }
	//여러 스레드가 실행 가능한 영역	
}

ex.

Thread 생성자 자체에 이름을 매개변수로 받는 생성자가 있음

public class Worker extends Thread {
	Work work; // 일
	int workLoad; // 얼마나 일해라 50
	
	// thread에 이름 지정
	public Worker(Work work, int workLoad, String name) {
		super(name); // new Thread(name);
		this.work = work;
		this.workLoad = workLoad;
	}
	
	// Thread로 수행되는 메소드
	public void run() {
		for (int i=1; i<=workLoad; i++) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			// 동기화 (객체) {}
			synchronized (work) { // 공유 객체가 자신이면 this 넣음
			// 전체 스레드가 동시에 접근하지 못하고 한번에 하나만 접근하도록 함
				work.addCnt(); //++ ++ 50번				
			}
						
			// 현재 스레드의 이름 출력
			System.out.println(Thread.currentThread().getName() + " -> " + work.toString());
		}
	}
}
public class ThreadWorkTest1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Work work = new Work();
		Worker worker1 = new Worker(work, 50, "1번 일꾼");
		Worker worker2 = new Worker(work, 50, "2번 일꾼");
	
		// 만약 Thread 상속 안받고 그냥 run이라는 메소드를 실행했으면
		// worker1의 업무가 끝날때까지 기다려야했지만, 스레드를 사용하면
		// 일을 병렬적으로 시킬 수 있음
		
		worker1.start();
		worker2.start();
		
		// 둘다 일하면서 숫자 ++ 하는데 최종적으로 증가하는 수는 50 + 50이 아니야..
        // 객체에 동시에 접근하면서 충돌 발생..
	}

}

class Work {
	int workCnt; // 일거리 갯수
	
	public Work() {
		workCnt = 0;
	}
	
	public void addCnt() {
		workCnt++;
	}
	
	public String toString() {
		return String.valueOf(workCnt);
	}
}

스레드 상태 제어

1. sleep() (Thread 클래스 메소드)

: 주어진 시간동안 스레드를 일시 정지 상태로 만들고 주어진 시간이 지나면 자동적으로 실행 대기 상태

try {
	Thread.sleep(1000);
} catch(InterruptedException e) {
	// interrupt() 메소드가 호출되면 실행
}

2. join() (Thread 클래스 메소드)

: join 메소드를 호출한 스레드는 일시 정지 상태가 된다. 실행대기 상태로 가려면 join 메소드를 멤버로 가지는 스레드가 종료되거나 매개값으로 주어진 시간이 지나야함

public class JoinExample {
	public static void main(String[] args) {
    	SumThread sumThread = new SumThread();
        sumThread.start();
    
    	try {
        	// sumThread가 종료할 때까지 메인 스레드를 일시 정지시킴
            sumThread.join();
        } catch(InterruptedException e) {
        }
    
    	System.out.println("1~100 합: " + sumThread.getSum());
    }
}

3. wait() (object 클래스 메소드)

: 동기화 블록 내에서 스레드를 일시 정지 상태로 만든다. 매개값으로 주어진 시간이 지나면 자동적으로 실행 대기 상태가 되고, 시간이 주어지지 않으면 notify, notifyAll에 의해 실행 대기 상태로 갈 수 있음

4. notify(), notifyAll() (object 클래스 메소드)

: 동기화 블록 내에서 wait 메소드에 의해 일시 정지 상태에 있는 스레드를 실행 대기 상태로 만든다
: notify는 한개, notifyAll은 여러개
: Object 클래스에 선언된 메소드여서 모든 공유 객체에서 호출 가능하지만, 동기화 메소드 or 동기화 블록 내에서만 사용 가능

class WorkObject {
	public synchronized void methodA() {
	System.out.println("ThreadA의 methodA() 작업 실행");
	// 일시 정지 상태에 있는 ThreadB를 실행 대기 상태로 만듦
	notify();
	try {
		// ThreadA를 일시 정지 상태로 만듦
		wait();
	} catch(InterruptedException e) {
	}
	}
	
	public synchronized void methodB() {
	System.out.println("ThreadB의 methodB() 작업 실행");
	// 일시 정지 상태에 있는 ThreadA를 실행 대기 상태로 만듦
	notify();
	try {
		// ThreadB를 일시 정지 상태로 만듦
		wait();
	} catch(InterruptedException e) {
	}
	}
}
profile
안녕하세요!

0개의 댓글