Thread

jinkyung·2021년 1월 15일
0

JAVA2

목록 보기
32/35

process : 집
Thread : 일을 하는 주체, 사람

모든 스레드는 스택에 공간을 가지게 된다.

스레드만드는 두가지 방법

1) thread클래스 상속 -> run 메소드 오버라이드

객체를 만들어 start메소드를 실행시키면 run메소드를 시작한다.

각각의 스레드가 독립적으로 실행된다.

2)Runnable 인터페이스를 상속받아 구현한다.

클래스가 어떤 클래스를 이미 상속받은 경우에 쓴다 (자바는 다중상속이 안되니까 )

그러나 스레드 클래스 객체의 힘을 빌려야한다. 혼자 실행할 수 없다.

jvm에 있는 스레드를 할당해주는 기능이 thread 클래스에 있기 때문에.

레지스터 - 책상, 메모리 -사물함



1) 싱글코어

스레드 a의 1,2,3의 과정이 끝날 때까지 제어권을 넘겨주면 안된다.

2)멀티코어 : cpu 여러개

결국 싱글코어든 멀티코어든 공유변수를 사용하면 문제가 발생할 수 있다.

(연산의 양이 많으면 많을수록, 스레드가 많으면 많을 수록 값이 왜곡될 가능성이 높아진다. )

--> 공유 변수를 사용하는 과정을 보호해야 한다. (ex.화장실)

= 동기화가 필요하다.


동기화

static 필드는 static synchronized로 동기화 처리

package ex06.thread.thread06;

class Anum{
	static int num = 0;
	
//	이 메서드가 시작하고 끝날 때까지 다른 스레드의 진입을 허용하지 않겠다
//	즉 메서드 처리동안 1개 스레드만 연산가능하다
	static synchronized void accumulate(int val) {
		/*
		우리 생각 :  눈으로 보는 코드는 1줄
		실제 동작 : 1) num -> register
                 2) val -> register
                 3) cpu(ALU) : num+val -> register
				 4) register -> num
		*/
		num += val;
	}
}

class Sum implements Runnable{
	
	//static int num = 0;	  // static변수는 Class에 1개만 존재, 모든 객체가 공유
	int start, end;
	
	Sum(int start, int end){
		this.start = start;
		this.end = end;
	}

	@Override
	public void run() {
		// 아래의 num은 모든 객체가 공유하므로 
		// Context Switching시 변수의 값이 왜곡될 수 있다
		// 그러므로 왜곡되지 않도록 하는 처리가 필요하다
		// 이를 스레드 (값의) 동기화라고 한다
		for(int i=start;i<=end;i++)
			Anum.accumulate(i);
	}
	
}

public class SyncThread {
	public static void main(String[] args) throws InterruptedException {
		Sum sum0 = new Sum(1, 50);
		Sum sum1 = new Sum(51, 100);
		
		Thread t0 = new Thread(sum0);
		Thread t1 = new Thread(sum1);
		
		t0.start();
		t1.start();
		
		//스레드는 독립적으로 처리되는 리소스이므로 main스레드와 자식스레드는 별개로 동작한다
		//자식 스레드가 종료될 때까지 대기
		t0.join();   //sum0의 run()이 리턴되면 join()을 리턴
		t1.join();   //sum1의 run()이 리턴되면 join()을 리턴
		
		System.out.println("1~100까지의 합 : " + Anum.num);
	}
}

일반 필드

package ex06.thread.thread06;

class Anum{
	 int num = 0;
	
	 synchronized void accumulate(int val) {
		num += val;
	}
}

class Sum implements Runnable{
	Anum aNum;
	int start, end;
	
	Sum(Anum aNum, int start, int end){
		this.aNum = aNum;
		this.start = start;
		this.end = end;
	}

	@Override
	public void run() {
 		for(int i=start;i<=end;i++)
			aNum.accumulate(i);
	}
	
}

public class SyncThread {
	public static void main(String[] args) throws InterruptedException {
		Anum aNum = new Anum();		//2개의 스레드가 공유하는 객체 
		Sum sum0 = new Sum(aNum, 1, 50);
		Sum sum1 = new Sum(aNum, 51, 100);
		
		Thread t0 = new Thread(sum0);
		Thread t1 = new Thread(sum1);
		
		t0.start();
		t1.start();
		
		t0.join();   
		t1.join();  
		
		System.out.println("1~100까지의 합 : " + aNum.num);
	}
}

부분동기화

package ex06.thread.thread08;

class Anum{
	 int num = 0;
//	만약 메서드의 코드가 길다. 
//	그런데 어떤 부분은 동기화가 필요하고,
//	어떤 부분은 필요없는 부분이 있을 수 있다.
//  그런데 메소드에 synchronized를 주면 전체를 동기화하므로 속도가 느려질 것이다. -->성능저하 
//  =>이럴 경우는 부분 동기화를 해주면 된다.
	 
	 void accumulate(int val) {
//		 모든 Class는 Object의 상속을 받는다. 
//		 Object는 스레드에 대한 lock키가 내장되어 있다. 
//		 그러므로 1개의 동기화가 필요할 때는 자신의 객체를 자물쇠로 사용하면 된다. 
//       -> 연산의 문제가 생길 부분만 이렇게 동기화시키면 된다. 
		 synchronized(this) {
			 num += val;
		 }
	}
}

class Sum implements Runnable{
	Anum aNum;
	int start, end;
	
	Sum(Anum aNum, int start, int end){
		this.aNum = aNum;
		this.start = start;
		this.end = end;
	}

	@Override
	public void run() {
 		for(int i=start;i<=end;i++)
			aNum.accumulate(i);
	}
	
}

public class SyncThread {
	public static void main(String[] args) throws InterruptedException {
		Anum aNum = new Anum();		//2개의 스레드가 공유하는 객체 
		Sum sum0 = new Sum(aNum, 1, 50);
		Sum sum1 = new Sum(aNum, 51, 100);
		
		Thread t0 = new Thread(sum0);
		Thread t1 = new Thread(sum1);
		
		t0.start();
		t1.start();
		
		t0.join();   
		t1.join();  
		
		System.out.println("1~100까지의 합 : " + aNum.num);
	}
}

누적차 메서드도 생성

package ex06.thread.thread09;

class Anum {
	int accuNum = 0;
	int diffNum = 0;

	void accumulate(int val) {
		synchronized (this) {
			accuNum += val;
		}
	}

	void calcDiff(int val) {
		diffNum -= val;
	}
}

class Sum implements Runnable {
	Anum aNum;
	int start, end;

	Sum(Anum aNum, int start, int end) {
		this.aNum = aNum;
		this.start = start;
		this.end = end;
	}

	@Override
	public void run() {
		for (int i = start; i <= end; i++)
			aNum.accumulate(i);
	}

}

class Minus implements Runnable {
	Anum aNum;
	int start, end;

	Minus(Anum aNum, int start, int end) {
		this.aNum = aNum;
		this.start = start;
		this.end = end;
	}

	@Override
	public void run() {
		for (int i = start; i <= end; i++)
			aNum.calcDiff(i);
	}

}



public class SyncThread {
	public static void main(String[] args) throws InterruptedException {
		Anum aNum = new Anum();
		
		//누적 합을 구하기 위한 스레드 
		Sum sum0 = new Sum(aNum, 1, 50);
		Sum sum1 = new Sum(aNum, 51, 100);
		Thread t0 = new Thread(sum0);
		Thread t1 = new Thread(sum1);
		
		//누적 차를 구하기 위한 스레드 
		Minus minus0 = new Minus(aNum, 1, 50);
		Minus minus1 = new Minus(aNum, 51, 100);
		Thread t2 = new Thread(minus0);
		Thread t3 = new Thread(minus1);

		t0.start();
		t1.start();
		t2.start();
		t3.start();

		t0.join();
		t1.join();
		t2.join();
		t3.join();

		System.out.println("1~100까지의 누적합 : " + aNum.accuNum);
		System.out.println("1~100까지의 누적차 : " + aNum.diffNum);
	}
}

0개의 댓글

관련 채용 정보