멀티 태스킹은 여러 개의 작업을 동시에 실행하는 기법이다.
멀티 스레딩(multi-threading)
병렬작업의 아이디어를 하나의 애플리케이션 안으로 가져온 것이다.
각각의 작업을 스레드(thread)라고 한다.
사용이유
여러가지 작업을 동시에 진행할 때 속도를 빠르게 하기 위해 사용
프로세스와 스레드
- 컴퓨터에는 프로세스(process)와 스레드(thread)라는 2가지의 실행 단위가 있다.
- 프로세스 : 하드디스크에 있는 프로그램이 램으로 로드되는 것.
- 모든 프로세스는 반드시 스레드를 하나 이상 가진다.
스레드 예제
public class ThreadEx01 {
public static void sub1() {
for (int i = 1; i <= 5; i++) {
try {
System.out.println("start1 thread : " + i);
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void sub2() {
for (int i = 1; i <= 5; i++) {
try {
System.out.println("start2 thread : " + i);
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// main thread
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
sub1();
});
t1.start();
// 실을 만드는 것
Thread t2 = new Thread(() -> {
sub2();
});
t2.start(); // 실을 시작하는것
} // main 스레드 종료
}
t1.start()와 t2.start()는 순차적으로 실행 되는 것이 아니라 동시에 같이 실행된다.
람다식을 이용해서 스레드를 작성하는것이 간편하다.
class MyFile {
// 하드디스크 기록 (I/O)
public void write() {
try {
Thread.sleep(5000); // sleep은 예외처리가 필요함
System.out.println("파일 쓰기 완료");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class 화가 {
public void 그림그리기() {
System.out.println("그림 그리기 완료");
}
}
public class ThreadEx02 {
public static void main(String[] args) {
new Thread(() -> {
MyFile mf = new MyFile();
mf.write();
}).start();
화가 h = new 화가();
h.그림그리기();
}
}
데드락
데드락(교착 상태)는 멀티 스레딩에서 얼마든지 나타날 수 있다. 교착 상태는 첫 번째 스레드가 두 번째 스레드가 획득한 객체 락을 기다리고 있고, 두 번째 스레드는 첫 번째 스레드가 획득한 객체 락을 기다리는 상황에서 발생할 수 있다. 두 스레드가 서로 상대방이 가진 락을 기다리고 있기 때문에, 아무리 시간이 경과하여도 교착 상태가 해결될 수 없다.
→ 프로그램을 재시작 하는 방법 말고는 교착 상태를 해결하는 방법은 없다.
→ 교착 상태가 일어나지 않도록 하는 것이 제일 중요하다.(동기화 사용)
동기화
- 스레드가 동일한 메모리를 사용하기 때문에 일어나는 2가지 문제가 스레드 간섭(thread interference), 메모리 불일치 오류(memory consistency error)이다.
- 위의 스레드 예제의 경우처럼 t1.start()와 t2.start()가 같이 실행되는 것.
- 이 오류를 막는 도구를 동기화(synchronization)라고 한다.
임계 영역(critical section) : 동시에 사용하면 안 되는 자원을 하나의 스레드가 사용(락 설정)시작 부터 끝날 때(락 해제)까지 한번에 하나의 스레드만 실행 가능
동기화 사용 방법 : 공유 데이터를 조작하는 메소드 앞에 synchronized를 붙인다.
class Printer{
synchronized void print(int[] arr){ // synchronized 입력
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
try{
Thread.sleep(100);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
class MyThread1 extends Thread{
Printer prn;
int[] myarr = {10, 20, 30, 40, 50};
MyThread1(Printer prn) {
this.prn = prn;
}
public void run(){
prn.print(myarr);
}
}
class MyThread2 extends Thread{
Printer prn;
int[] myarr = {1,2,3,4,5};
public MyThread2(Printer prn) {
this.prn = prn;
}
public void run(){
prn.print(myarr);
}
}
public class TestSynchro {
public static void main(String[] args) {
Printer obj = new Printer();
MyThread1 t1 = new MyThread1(obj);
MyThread2 t2 = new MyThread2(obj);
t1.start();
t2.start();
}
}
Share article