thread

프로세스와 스레드

스레드의 생성 및 실행

Thread 클래스 상속받아서 스레드 생성

class ThreadExtend extends Thread {
    public void run() {
        System.out.println("Thread 상속받는 방법");
        for (int i=0; i<50; i++) {
            System.out.println("ThreadExtend:"+i);
        }
    }
}

Runnable 인터페이스 구현으로 스레드 정의

class RunnableImple implements Runnable {
    public void run() {
        System.out.println("Runnable 구현하는 방법");
        for (int i=0; i<50; i++) {
            System.out.println("RunnableImple:"+i);
        }
    }
}

스레스 스타트 start()

package chapter17;

public class ThreadEx {

    public static void main(String[] args) {

        // Thread 상속받는 방법
        ThreadExtend t1 = new ThreadExtend();

        // Runnable 구현하는 방법
        Runnable r = new RunnableImple();
        // Thread 생성자의 매개변수로 전달
        Thread t2 = new Thread(r);

        t1.start();
        t2.start();

    }

Runnable 인터페이스 익명 클래스 구현으로 스레드 정의

package chapter17;

public class ThreadEx2 {

    public static void main(String[] args) {

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t1 스레드 시작");
                for (int i=0; i<50; i++) {
                    System.out.println("t1 : "+i);
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t2 스레드 시작");
                for (int i=0; i<50; i++) {
                    System.out.println("t2 : "+i);
                }
            }
        });

        t1.start();
        t2.start();

    }

}

람다표현식으로 스레드 정의

package chapter17;

public class ThreadEx3 {

    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            System.out.println("t1 스레드 시작");
            for (int i=0; i<50; i++) {
                System.out.println("t1 : "+i);
            }
        });

        Thread t2 = new Thread(() -> {
            System.out.println("t2 스레드 시작");
            for (int i=0; i<50; i++) {
                System.out.println("t2 : "+i);
            }
        });

        t1.start();
        t2.start();

    }

}

스레드 우선순위

package chapter17;

public class ThreadEx4 {

    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            System.out.println("t1 스레드 시작");
            for (int i=0; i<50; i++) {
                System.out.println("t1 : "+i);
            }
        });

        Thread t2 = new Thread(() -> {
            System.out.println("t2 스레드 시작");
            for (int i=0; i<50; i++) {
                System.out.println("t2 : "+i);
            }
        });

        // 우선순위 지정
        t1.setPriority(MAX_PRIORITY ); // t1이 먼저 종료됨
        t2.setPriority(3);

        t1.start();
        t2.start();

    }

}

쓰레드 상태 변화 및 제어

sleep(n)

package chapter17;

public class ThreadEx7 {

    public static void main(String[] args) {

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0; i<10; i++) {
                    System.out.println("t1:"+i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {}
                }
                System.out.println("스레드 실행 종료");
            }
        });


        t1.start();

    }

}

join() 메서드

class Sum extends Thread {
    int sum = 0;
    @Override
    public void run() {
        for (int i=1; i<=100; i++) {
            sum += i;
        }
    }
}

2개의 스레드 처리

package chapter17;

public class ThreadEx8 {

    public static void main(String[] args) {

        Sum t1 = new Sum();
        Sum t2 = new Sum();

        t1.start();
        t2.start();
        try {
            t1.join(); // t1 스레드가 종료될때까지 대기
            t2.join(); // t2 스레드가 종료될때까지 대기
        } catch (InterruptedException e) {

        }
        System.out.println("두 스레드의 sum 합계 = "+(t1.sum+t2.sum));

    }

}

yield() 메서드

package chapter17;

public class ThreadEx9 {

    public static void main(String[] args) {

        YieldThread t1 = new YieldThread();
        YieldThread t2 = new YieldThread();

        t1.start();
        t2.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}

        t1.isContinue = false; // t1 양보

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}

        t1.isContinue = true; // t1 다시 실행, 주석달면 t2만 실행되고 끝남

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {}

        // 스레드 종료
        t1.isBreak = true;
        t2.isBreak = true;

    }

}

class YieldThread extends Thread {
    boolean isBreak = false;
    boolean isContinue = true;

    @Override
    public void run() {
        while(!isBreak) {
            if (isContinue) {
                System.out.println(getName()+" 실행 중");
            }else {
                Thread.yield();
            }
        }
        System.out.println(getName()+" 종료");
    }
}

스레드 동기화

// 플레이어1 스레드
class Player1 extends Thread {
    private SmartPhoneGame game;

    public void setSmartPhoneGame(SmartPhoneGame game) {
        this.setName("Player1"); // 스레드 이름 지정
        this.game = game;
    }

    @Override
    public void run() {
        game.increaseLevel();
    }
}
// 플레이어2 스레드
class Player2 extends Thread {
    private SmartPhoneGame game;

    public void setSmartPhoneGame(SmartPhoneGame game) {
        this.setName("Player2"); // 스레드 이름 지정
        this.game = game;
    }

    @Override
    public void run() {
        game.increaseLevel();
    }
}

동기화가 되지 않은 경우

// 스마트폰게임 클래스
class SmartPhoneGame {
    private int level; // 레벨

    public int getLevel() {
        return this.level;
    }

    public void increaseLevel() {
        while (true) {
            this.level++; // 레벨 1씩 증가
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {}
            // 현재 스레드의 이름과 레벌 출력
            System.out.println(Thread.currentThread().getName()+" Level : " + this.level);

            // 레벨이 10의 배수가 되면 종료
            if (this.level % 10 == 0) break;
        }
    }


}

테스트

package chapter17;

public class ThreadEx10 {

    public static void main(String[] args) {

        // 게임 객체 생성
        SmartPhoneGame game = new SmartPhoneGame();

        // 플레이어1 객체 생성 후 스레드 실행
        Player1 p1 = new Player1();
        p1.setSmartPhoneGame(game);
        p1.start();

        // 플레이어2 객체 생성 후 스레드 실행
        Player2 p2 = new Player2();
        p2.setSmartPhoneGame(game);
        p2.start();

    }

}

동기화한 경우

// 스마트폰게임 클래스
class SmartPhoneGame {
    private int level; // 레벨

    public int getLevel() {
        return this.level;
    }


    public synchronized void increaseLevel() {
        while (true) {
            this.level++; // 레벨 1씩 증가
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {}
            // 현재 스레드의 이름과 레벌 출력
            System.out.println(Thread.currentThread().getName()+" Level : " + this.level);

            // 레벨이 10의 배수가 되면 종료
            if (this.level % 10 == 0) break;
        }
    }

스레드 간에 교대로 작업 (협업)

// 스마트폰게임 클래스
class SmartPhoneGame {
    private int level; // 레벨

    public int getLevel() {
        return this.level;
    }


    public synchronized void increaseLevel() {
        while (true) {
            this.level++; // 레벨 1씩 증가
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {}
            // 현재 스레드의 이름과 레벌 출력
            System.out.println(Thread.currentThread().getName()+" Level : " + this.level);
            if (this.level == 5) {

                try { 
                    wait(); // 실행 -> 대기 상태
                    notifyAll(); // 대기 -> 실행 가능
                } catch (InterruptedException e) {}
                break;
            }


            // 레벨이 10의 배수가 되면 종료
            if (this.level % 10 == 0) break;
        }
    }


}

스레드 예제

// 엄마 스레드
class Mother extends Thread {
    Account account;

    Mother(Account account) {
        super("엄마");
        this.account = account;
    }

    @Override
    public void run() {
        while(true) {
            try {
                account.deposit();
                sleep((int)(Math.random()*2000));
            } catch (InterruptedException e) {
                break;
            }
        }
    }
}

//아들 스레드
class Son extends Thread {
    Account account;

    Son(Account account) {
        super("아들");
        this.account = account;
    }

    @Override
    public void run() {
        while(true) {
            try {
                account.withdraw();
                sleep((int)(Math.random()*300));
            } catch (InterruptedException e) {
                break;
            }
        }
    }
}
// 통장 클래스
class Account {
    int money;
    synchronized void withdraw() {
        while(money == 0) {
            try {
                wait();
            }catch(InterruptedException e) {
                break;
            }
        }
        notifyAll();
        if(money > 0) {
            System.out.println(Thread.currentThread().getName() + money + "원 출금");
            money = 0;
        }
    }
    synchronized void deposit() {
        while(money > 0) {
            try {
                wait();
            } catch(InterruptedException e) {
                break;
            }
        }
        // 랜덤 입금 1~5만원
        money = (int)((Math.random()*5)+1)*10000;
        notifyAll();
        System.out.println();
        System.out.println(Thread.currentThread().getName() + money + "원 입금");
    }
}
package chapter17;

public class ThreadEx14 {

    public static void main(String[] args) {

        // 통장 객체 생성
        Account acc = new Account();

        // 엄마스레드 객체 생성
        Mother mother = new Mother(acc);
        // 아들스레드 객체 생성
        Son son = new Son(acc);


        mother.start();
        son.start();

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {}

        // 스레드 중지
        son.interrupt();
        mother.interrupt();

    }

}