🎨 Programming/JAVA

[JAVA] 31. 스레드(thread) - 2

ryang x2 2021. 3. 22. 13:17
728x90
반응형

● 스레드 스케줄링 

스레드의 개수가 코어의 수보다 많을 경우 스레드를 어떤 순서에 의해 동시성으로 실행할 것인지를 계획하는 것입니다.
아주 짧은 시간에 스레드의 run 메서드를 번갈아가면서 실행합니다.

 

* 스레드 이름 확인하는 방법 

class ThreadA extends Thread {
    public ThreadA(){
        setName("ThreadA"); // 스레드 이름을 설정
    }

    @Override
    public void run() {
        for (int i=0; i<10; i++){
            System.out.println(getName() + "스레드가 출력합니다.");
        }
    }
}

class ThreadB extends  Thread{
    @Override
    public void run() {
        for (int i=0; i<10; i++){
            System.out.println(getName() + "스레드가 출력합니다.");
        }
    }
}

public class Thread4 {
    public static void main(String[] args) {
        Thread mainThread = Thread.currentThread(); // currentThread 현재의 스레드가 무엇인지 확인
        System.out.println("프로그램 시작");
        System.out.println("현재 스레드 이름 : " + mainThread.getName());

        ThreadA thA = new ThreadA();
        System.out.println("작업 스레드 이름 : " + thA.getName());
        thA.start();

        ThreadB thB = new ThreadB();
        System.out.println("작업 스레드 이름 : " + thB.getName());
        thB.start();
    }
}

 

 

● 우선 순위(priority) 방식 

1. 우선 순위가 높은 스레드가 실행상태를 더 많이 가져갑니다.
2. 객체에 우선 순위를 부여하여 개발자가 제어를 합니다.
3. 1부터 10까지 우선순위, 높으면 먼저 실행합니다.
) thread.setPriority(우선순위값);


* 우선순위가 높은 스레드가 실행 기회를 더 많이 가지기 때문에 우선순위가 낮은 스레드보다
작업을 하더라도 빨리 끝낼 수 있습니다.(작업량에 따라 다름)

 

class CalcThread extends Thread{
    public CalcThread(String name){
        setName(name); // th0 th1 th2 ... th9
    }
    public void run(){
        for (int i=0; i<100000; i++){
            System.out.println(getName());
        }
    }
}
public class Thread5 {
    public static void main(String[] args) {
        for (int i=0; i<10; i++){
            Thread th = new CalcThread("th"+i);
            if (i == 9){
                th.setPriority(Thread.MAX_PRIORITY); // MAX_PRIORITY : 10
            }else{
                th.setPriority(Thread.MIN_PRIORITY); // MIN_PRIORITY : 1 // NORM_PRIORITY(5)
            }
            th.start();
        }
    }
}

 

● 동기화 

1. thread1 필드 값을 변경
2. thread2 필드 값을 변경
3. thread1 필드의 값을 사용
4. 문제 발생!

* 해결 방법 : synchronized 메소드로 해결합니다.
* synchronized : 객체에 잠금을 걸어두어 하나의 스레드만이 접근 가능하고
나머지 스레드는 대기하도록 만듭니다. (임계영역 : 단 하나의 스레드만 실행 할 수 있는 영역)

method() 계산에 관련된 메소드가 있을때에는 동기화가 필요하다.

 

1) MyCount 생성

public class MyCount {
    private int cnt;

    public int getCnt() {
        return cnt;
    }

    public void setCnt(int cnt) {
        this.cnt = cnt;
    }

    public synchronized void increment(){ // synchronized 추가
        cnt++;
    }
}

 

2) CountThread 생성 Thread 상속

public class CountThread extends Thread {
    MyCount counter;
    int num;

    public CountThread(MyCount counter, int num) {
        this.counter = counter;
        this.num = num;
    }

    public void run() {
        synchronized (counter) { // synchronized 추가
            counter.setCnt(num); // MyCounter 에 값을 세팅
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName() + " cnt : " + counter.getCnt());
        }
    }
}

3) main 

public class Thread6 {
    public static void main(String[] args) {
        MyCount counter = new MyCount();
        Thread th1 = new CountThread(counter, 100);
        th1.setName("첫번째 스레드");
        Thread th2 = new CountThread(counter, 200);
        th2.setName("두번째 스레드");

        th1.start();
        th2.start();

        System.out.println("counter cnt : " + counter.getCnt());
    }
}

 

* join() : 다른 스레드의 종료를 기다립니다.

class SumThread extends Thread {
    private long sum;

    public long getSum() {
        return sum;
    }

    public void setSum(long sum) {
        this.sum = sum;
    }

    public void run(){
        for (int i=0; i<=100; i++){
            sum += i;
        }
    }

    public String toString(){
        return "스레드 총합 : " + sum;
    }
}

public class Thread7 {
    public static void main(String[] args) {
        System.out.println("메인 스레드 시작");
        SumThread sumThread = new SumThread();
        sumThread.start();
        try{
            sumThread.join();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("1~100 합 : " + sumThread.getSum());
    }
}

 

join()을 사용하여 다른 스레드 종료를 기다립니다.
* thread 1, 2, 3을 실행하고 thread3이 제일 먼저 끝나게 됩니다.
thread 1 다음 thread2 다음 thread3 순서로 join을 하여 마지막으로
thread 3 join되어 결과는 thread3이 처음 또는 두번째로 끝나게 됩니다.

import java.util.concurrent.TimeUnit;

class JoinTask implements Runnable {
    private static int count = 0;
    private int id;
    private long sleepTime;
    private String taskId;

    @Override
    public void run() {
        String currentThreadName = Thread.currentThread().getName();
        System.out.println("[현재 스레드 이름 : " + currentThreadName + ", " + taskId + " ]");
        for (int i = 0; i<4; i++){
            System.out.println("[현재 스레드 이름 : " + currentThreadName + ", " + taskId + " ] >> for문");
            try{
                TimeUnit.MILLISECONDS.sleep(sleepTime);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println("[현재 스레드 이름 : " + currentThreadName + ", " + taskId + " ] >> 완료");
    }
    public JoinTask(long sleepTime){
        this.id = ++count;
        this.taskId = "Task: " + id;
        this.sleepTime = sleepTime;
    }
}

public class Thread8 {
    public static void main(String[] args) throws InterruptedException {
        String currentThreadName = Thread.currentThread().getName();
        System.out.println("[" + currentThreadName + "]" + " 스레드 시작!");

        Thread thread1 = new Thread(new JoinTask(200), "첫번째 스레드");
        Thread thread2 = new Thread(new JoinTask(500), "두번째 스레드");
        Thread thread3 = new Thread(new JoinTask(100), "세번째 스레드");

        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        System.out.println("[" + currentThreadName + "]" + " join! " + thread1.getName());
        thread2.join();
        System.out.println("[" + currentThreadName + "]" + " join! " + thread2.getName());
        thread3.join();
        System.out.println("[" + currentThreadName + "]" + " join! " + thread3.getName());

        System.out.println("[" + currentThreadName + "]" + " 스레드 종료");
        }
}

 

728x90
반응형