프로세스와 스레드 (축약)

  • 프로세스(Process)
    : 프로세스는 데이터/컴퓨터자원/스레드로 구성되어 있다. 프로세스는 실행중인 애플리케이션이다. 실행에 필요한 만큼 메모리를 할당받아 프로세스가 된다.

  • 스레드 (Thread)
    : 데이터와 컴퓨터자원을 활용하여 소스코드를 실행한다. 스레드는 코드의 실행 흐름이다.

  • 메인스레드 (Main thread)
    : Main스레드가 자바의 main메서드를 처음부터 끝까지 순차적으로 실행시킨다. 코드 끝이나 return문을 만나면 실행을 종료한다.

  • 싱글스레드
    단방향으로 메인스레드만 가지고 있는 프로세스.
    메인스레드가 종료되기 전까지 다른 동작을 실행못함

  • 멀티 스레드 프로세스
    : 하나의 프로세스가 여러개의 스레드를 갖는 것

  • 멀티스레드 (Multi-Thread)
    : 여러개의 스레드가 동시에 작업을 수행하는 것
    ex) 카톡에서 사진을 보내면서 채팅하기같은 여러가지 작업을 동시 수행하는 것

스레드 생성과 실행

작업 스레드 생성하고 실행하기

작업스레드를 활용한다는 것은, 작업스레드가 수행할 코드를 작성하고 생성하여 실행시키는 것을 의미한다.

스레드가 수행할 코드는 클래스 내부에 작성되며 run() 메서드 내에서 작성되어야 한다.

두 가지 방법이 있다.

  1. Runnable 인터페이스implements한 클래스에서 run()을 구현하여 스레드를 생성하고 실행하는 방법

1) Runnable인터페이스를 구현한다.
2) 추상메서드로 있는 public abstract void run(); 를 오버라이드한다.

class ThreadTask1 implements Runnable{
    @Override
    public void run() {}
}

3) run()메서드 바디에 새롭게 생성된 작업스레드가 수행할 코드를 적어준다.

// run() 메서드 바디에 스레드가 수행할 작업 내용 작성
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.print("#");
        }
    }

4) 스레드를 생성한다.
Runnable을 구현한 객체를 인자로 전달하면서 Thread클래스를 인스턴스화 한다.

public class ThreadEx {
   public static void main(String[] args) {

    // Runnable 인터페이스를 구현한 task1 객체생성
        Runnable task1=new ThreadTask1();

    // 스레드 클래스의 인스턴스 thread1만들기 인자값으로 Runnable 구현객체를 전달한다.
        Thread thread1=new Thread(task1);
        
    //위의 두 줄을 축약한 한줄버젼
        Thread thread2 = new Thread(new ThreadTask1());
        
    // 작업스레드를 실행시켜 run() 내부 코드 처리
    thread1.start();
    }
}

5) 스레드를 생성하는 것으로 run()내부 코드가 실행되지는 않는다. start() 메서드를 호출해주어야 한다.

6) main()에 run()에 작성된 코드를 복사해보자!

public class ThreadExample1 {
    public static void main(String[] args) {
        Runnable task1 = new ThreadTask1();
        Thread thread1 = new Thread(task1);

        thread1.start();

        // 반복문 추가
        for (int i = 0; i < 100; i++) {
            System.out.print("@");
        }
    }
}

class ThreadTask1 implements Runnable {
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.print("#");
        }
    }
}

▽ 출력결과

"@"는 main()에서 "#"은 run()메서드에서 출력했다. 출력결과를 보면 @와 #은 섞여있다.

⭐️ 메인스레드와 작업스레드가 동시에 병렬로 실행되면서 main과 run메서드의 코드를 실행시켰기 때문에 두가지 문자가 섞여서 출력되었다.


  1. Thread 클래스를 상속받는 하위클래스에서 run()을 구현하여 스레드를 생성하고 실행하는 방법

1) 스레드 클래스를 extends(상속)한 클래스 작성한다.

// 스레드 클래스를 상속받는 클래스생성
class ThreadTask2 extends Thread{}

2) run()를 오버라이딩 한다.

class TgreadTask2 extends Thread{

    @Override
    public void run() {}
}

3) run()에 스레드가 수행할 작업 코드작성

public void run() {
        for(int i=0; i<100; i++){
            System.out.print("#");
        }
    }

4) 스래드클래스를 상속받은 클래스를 인스턴스화 하여 스레드 생성

public static void main(String[] args) {
   // 스레드 클래스를 상속받은 클래스를 인스턴스화 하기 
   ThreadTask2 thread2 = new ThreadTask2();

5) main메서드에 thread2.start(); 넣기

6) 아래의반복문 main()에 붙여넣기

public class ThreadExample2 {
    public static void main(String[] args) {
     // 스레드 클래스를 상속받은 클래스를 인스턴스화 하기
        ThreadTask2 thread2 = new ThreadTask2();

        thread2.start();

        for(int i=0; i<100; i++){
            System.out.print("@");
        }
    }
}

class ThreadTask2 extends Thread{
    @Override
    public void run() {
        for(int i=0; i<100; i++){
            System.out.print("#");
        }
    }
}
  1. Runnable 익명객체를 활용한 스레드 생성 및 실행

익명객체를 통해서는 클래스를 따로 정의하지 않고도 스레드를 생성하고 실행시킬 수 있다.

public class ThreadExample1 {
    public static void main(String[] args) {
				
        // 익명 Runnable 구현 객체를 활용하여 스레드 생성
        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.print("#");
                }
            }
        });

        thread1.start();

        for (int i = 0; i < 100; i++) {
            System.out.print("@");
        }
    }
}
  1. Thread 익명 하위 객체를 활용한 스레드 생성 및 실행
public class ThreadExample2 {
    public static void main(String[] args) {

        // 익명 Thread 하위 객체를 활용한 스레드 생성
        Thread thread2 = new Thread() {
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.print("#");
                }
            }
        };

        thread2.start();

        for (int i = 0; i < 100; i++) {
            System.out.print("@");
        }
    }
}

스레드 상태와 실행제어 메서드() 한눈에 보기

  • Thread.sleep(n); 을 사용할 땐 try...catch문을 사용한다.

  • 임계영역과 락?
    : 은 임계영역을 포함하고 있는 객체에 접근할 수 있는 권한이다.
    : 임계영역이란, 하나의 스레드 코드만 실행할 수 있는 코드 영역을 의미한다. synchronized키워드를 통해 임계영역을 설정 할 수 있다.

  1. 메서드 전체를 임계 영역으로 지정할때
    : 반환타입 앞에 synchronized키워드를 작성하면 된다.

    public synchronized boolean withdraw(int money)

  2. 특정 영역을 임계 영역으로 지정할 때
    : synchronized()안에 객체의 참조를 넣은 후 {}블럭 내에 코드를 작성하면 된다.

    synchronized (this){코드작성}

public boolean withdraw(int money) {
			synchronized (this) {
			    if (balance >= money) {
			        try { Thread.sleep(1000); } catch (Exception error) {}
			        balance -= money;
			        return true;
			    }
			    return false;
			}
	}
profile
기억을 위한 기록 :>

0개의 댓글