JAVA Thread Programming

김현수·2025년 4월 13일
0

Process

  • 하나의 program을 실행하는데 필요한 것을 나타내는 OS의 추상화
  • 자신의 address space에서 순차적으로 실행되는 stream
  • 실행 중인 program

Process에서 Process로 변환

PCB : Process 정보 저장

UNIX process

  • Process 0을 제외한 모든 process는 fork() system call에 의해 생성
    • fork()는 process table에 항목을 할당하고 child process에 고유한 PID를 할당
    • child는 parent process의 process image 복사본을 얻음
    • child와 parent 모두 fork() 이후 동일한 코드를 실행
main() {
	int pid;
    cout << "just one process so far" << endl;
    pid = fork();
    if (pid == 0)
    	cout << "i'm the child" << endl;
    else if (pid > 0)
    	cout << "i'm the parent" << endl;
    else
    	cout << "fork failed" << endl;
}

Threads

  • program 내에서 control의 하나의 sequential flow
  • thread는 program process의 context 내에서 실행되며 해당 process와 해당 환경에 할당된 resource를 활용
  • Thread의 구성
    • Program counter
    • Register set
    • Stack
  • 동일한 process share에 속한 threads
    • Code section
    • Data section
    • OS resources such as open files

Single and multithreaded program

address 주소의 최대값은 26412^{64} -1

Multi-process vs Multi-thread

Process

  • child process가 parent variable들의 복사본을 가져옴
  • 시작 비용이 높음
  • variable에 대한 concurrent access를 걱정할 필요가 없음

Thread

  • child process가 parent의 variable을 공유
  • 비교적 저렴한 시작 비용
  • variable에 대한 concurrent access가 문제

Programming JAVA threads

  • Java는 threads built-in이 있음 (java.lang.thread)
  • Application은 하나 이상의 thread로 구성

thread 생성 1

class MyThread extends Thread {
	public void run() {
    	// ...work to do
    }
}

MyThread t = new MyThread();
t.start();

위와 같이 thread를 실행하려면 run()을 실행

class ThreadDemo {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();
        for (int i = 0; i < 50; i++) {
            System.out.println("i = " + i + ", i * i = " + i * i);
        }
    }
}
class MyThread extends Thread {
    public void run() {
        for (int count = 1, row = 1; row < 20; row++, count++) {
            for (int i = 0; i < count; i++) {
                System.out.print('*');
            }
            System.out.print('\n');
        }
    }
}

위 코드에서 run() 먼저 실행

Thread Names

  • default name은 다음과 같은 format으로 정의함: Thread-No
    • Thread-1, Thread-2, ...
  • 생성자를 통해 사용자가 정의한 이름을 지정할 수 있음
Thread myThread = new Thread("HappyThread");
  • "setName(aString)"을 통해 사용 가능함
  • Thread class에는 thread name을 가져올 수 있는 'getName()" method가 있음
public class Loop3 extends Thread {
    public Loop3(String name) {
        super(name);
    }
    public void run() {
        for (int i = 0; i < 10000; i++) {
            System.out.println(getName() + " (" + i + ")");
            try {
                sleep(10);
            }
            catch (InterruptedException e) {

            }
        }
    }
    public static void main(String[] args) {
        Loop3 t1 = new Loop3("Thread 1");
        Loop3 t2 = new Loop3("Thread 2");
        Loop3 t3 = new Loop3("Thread 3");
        t1.start();
        t2.start();
        t3.start();
    }
}

Thread 생성 2

Java는 다중 상속을 허용하지 않음

  • Runnable interface는 하나의 method를 가지고 있음
    • public void run()
  • 즉, 다음과 같이 Runnable을 Implement로 받고 run()을 정의해야 함
class MyRunnable implements Runnable {
	public void run() {
    	System.out.println("MyRunnable.run()");
    }
}
class Main {
	public static void main(String[] args) {
    	MyRunnable myrun = new MyRunnable();
        Thread t1 = new Thread(myrun);
        t1.start();
        System.out.println("InsideMain()");
    }
}

Thread Priority

  • 모든 Java thread들은 priority value를 가지고 있음 (1~10)
  • Priority는 언제나 변경 가능
    • setPriority(int newPriority)
  • 초기 priority는 thread 생성 순위로 매김
  • Preemptive scheduling
    • JVM은 우선순위가 높은 thread를 우선시함

yield

  • CPU의 권리를 해제
  • static void yield()
    • scheduler가 다른 runnable thread를 선택할 수 있도록 허용함
    • 어떤 thread인지는 보장 X
class YieldThread extends Thread {
    public void run() {
        for (int count = 0; count < 4; count++) {
            System.out.println(count + "From: " + getName());
            yield();
        }
    }
}
class TestThread {
    public static void main(String[] args) {
        YieldThread first = new YieldThread();
        YieldThread second = new YieldThread();
        first.start();
        second.start();
        System.out.println("End");
    }
}

Thread identity

  • Thread.currentThread()
    • 실행중인 thread를 반환
  • running thread를 created thread와 비교

Thread sleep, suspend, resume

  • static void sleep(long millis)
    • 지정된 thread를 지정된 시간 만큼 잠금
  • void stop(), void suspend(), void resume()
    • Deprecated! -> 지금 안 쓰임

Thread Waiting & Status Check

  • void join(), void join(long), void join(long, int)
    • thread(A)는 thread(B)가 끝날때까지 기다림
      //thread A 안
      threadB.join() // B가 종료될 때까지 A는 sleep
  • boolean isAlive()
    • thread가 사작되고 중지되지 않은 경우 true로 반환
public class JoinThr {
    static public void main(String s[]) {
        MyThread1 Thread_a;
        MyThread2 Thread_b;
        Thread_a = new MyThread1();
        Thread_b = new MyThread2(Thread_a);

        System.out.println("Starting the threads...");
        Thread_a.start();
        Thread_b.start();
    }
}

class MyThread1 extends Thread {
    public void run() {
        System.out.println(getName() + " is running...");
        for (int i = 0; i < 4; i++) {
            try {
                sleep(500);
            }
            catch (InterruptedException e) {}
            System.out.println("Hello there, from" + getName());
        }
    }
}

class MyThread2 extends Thread {
    private Thread wait4me;
    MyThread2(Thread target) {
        super();
        wait4me = target;
    }
    public void run() {
        System.out.println(getName() + " is waiting for " + wait4me.getName() + "...");
        try {
            wait4me.join();
        }
        catch (InterruptedException e) {}
        System.out.println(wait4me.getName() + " has finished...");
        for (int i = 0; i < 4; i++) {
            try {
                sleep(500);
            }
            catch (InterruptedException e) {}
            System.out.println("Hello there, from" + getName());
        }
    }
}

output

Starting the threads...
Thread-0 is running...
Thread-1 is waiting for Thread-0...
Hello there, fromThread-0
Hello there, fromThread-0
Hello there, fromThread-0
Hello there, fromThread-0
Thread-0 has finished...
Hello there, fromThread-1
Hello there, fromThread-1
Hello there, fromThread-1
Hello there, fromThread-1

Thread synchronization

  • thread의 장점은 많은 일을 동시에 처리할 수 있음
  • thread의 문제점은 많은 일이 동시에 일어날 수 있음
  • Safety
    • 어떠한 나쁜 일도 일어나지 않음
    • race condition이 없음
  • Liveness
    • 결국 어떤 일이 일어남 : no deadlock

Race condition

ex. Bank Account

class Account {
	int balance;
    public void deposit(int val) {
    	balance = balance + val;
    }
}

thread가 account balance에 동시에 deposit을 하면 race condition이 됨

Thread Synchronization

  • object의 shared data에 대한 동시 접근
  • shared data에 대한 thread의 접근을 제한하는 방법이 필요
    • concurrency ⬇️
  • Critical Section의 Mutual Exclusion
    • object에 lock 추가
    • 모든 thread는 method를 실행하기 전 lock을 획득해야 함
    • 현재 lock을 사용할 수 없는 경우 thread가 차단
  • synchronized keyword를 사용해 controll accesss 가능
class Account {
	private int balance;
    public synchronized void deposit(int val) {
    	balance = balance + val;
    }
    public synchronized void withdraw(int val) {
    	balance = balance - val;
    }
}

0개의 댓글