public class TestThread extends Thread {
@Override
public void run() {
// Thread 수행작업
}
}
...
TestThread thread = new TestThread(); // Thread 생성
thread.start() // 쓰레드 실행
public class TestRunnable implements Runnable {
@Override
public void run() {
// 쓰레드 수행작업
}
}
...
Runnable run = new TestRunnable();
Thread thread = new Thread(run); // 쓰레드 생성
thread.start(); // 쓰레드 실행
public class Main {
public static void main(String[] args) {
Runnable task = () -> {
int sum = 0;
for (int i = 0; i < 50; i++) {
sum += i;
System.out.println(sum);
}
System.out.println(Thread.currentThread().getName() + " 최종 합 : " + sum);
};
Thread thread1 = new Thread(task);
thread1.setName("thread1");
Thread thread2 = new Thread(task);
thread2.setName("thread2");
thread1.start();
thread2.start();
}
}
public class Main {
public static void main(String[] args) {
Runnable task = () -> {
for (int i = 0; i < 100; i++) {
System.out.print("$");
}
};
Runnable task2 = () -> {
for (int i = 0; i < 100; i++) {
System.out.print("*");
}
};
Thread thread1 = new Thread(task);
thread1.setName("thread1");
Thread thread2 = new Thread(task2);
thread2.setName("thread2");
thread1.start();
thread2.start();
}
}
public class Main {
public static void main(String[] args) {
Runnable demon = () -> {
for (int i = 0; i < 1000000; i++) {
System.out.println("demon");
}
};
Thread thread = new Thread(demon);
thread.setDaemon(true);
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("task");
}
}
}
// ThreadGroup 클래스로 객체를 만듭니다.
ThreadGroup group1 = new ThreadGroup("Group1");
// Thread 객체 생성시 첫번째 매개변수로 넣어줍니다.
// Thread(ThreadGroup group, Runnable target, String name)
Thread thread1 = new Thread(group1, task, "Thread 1");
// Thread에 ThreadGroup 이 할당된것을 확인할 수 있습니다.
System.out.println("Group of thread1 : " + thread1.getThreadGroup().getName());
// ThreadGroup 클래스로 객체를 만듭니다.
ThreadGroup group1 = new ThreadGroup("Group1");
// Thread 객체 생성시 첫번째 매개변수로 넣어줍니다.
// Thread(ThreadGroup group, Runnable target, String name)
Thread thread1 = new Thread(group1, task, "Thread 1");
Thread thread2 = new Thread(group1, task, "Thread 2");
// interrupt()는 일시정지 상태인 쓰레드를 실행대기 상태로 만듭니다.
group1.interrupt();
sleep(): 현재 Thread를 지정된 시간동안 멈추게 함
자기자신에 대해서만 멈추게 할 수 있음
Thread.sleep(ms); : ms(밀리초) 단위로 설정됨
예외처리를 해야함
sleep 상태에 있는 동안 interrupt()를 만나면 다시 실행되기 때문
특정 Thread 지목해서 멈추게 하는 것은 불가능
interrupt(): 일시정지 상태인 Thread를 실행대기 상태로 만듦
join(): 정해진 시간동안 지정한 Thread가 작업하는 것을 기다림
시간을 지정하지 않았을 때는 지정한 Thread의 작업이 끝날 때를 기다림
yield(): 남은 시간을 다음 Thread에게 양보하고 Thread 자신은 실행대기 상태가 됨
synchronzed: 멀티 Thread는 여러 Thread가 한 Process의 자원을 공유해서 작업하기 때문에 서로에게 영향을 줄 수 있음 ➡️ 장애나 버그 발생 가능, 이러한 일을 방지하기 위해 한 Thread가 진행중인 작업을 다른 Thread가 침범하지 못하도록 막음
* 동기화 하려면 다른 Thread의 침법을 막아야하는 코드들을 임계영역으로 설정해야함
임계영역: Lock을 가진 단 하나의 Thread만 출입 가능 ➡️ 한 번에 한 Thread만 사용 가능
wait(): 실행중이던 Thread는 해당 객체의 대기실(waiting pool)에서 통지를 기다림
notify(): 해당 객체의 대기실(waiting pool)에 있는 모든 Thread 중에서 임의의 Threadaks 통지를 받음
wait(), notify() 순서 정리
침범을 막은 코드를 수행하다가 작업을 더 이상 진행할 상황이 아니면 ➡️ wait()을 호출하여 Thread가 Lock을 반납하고 기다리게 할 수 있음 ➡️ 그럼 다른 Thread가 Lock을 얻어 해당 객체에 대한 작업이 가능해짐 ➡️ 추후에 작업을 진행할 수 있는 상황이 되면 notify() 호출 ➡️ 작업을 중단했던 Thread가 다시 Lock을 얻어 진행이 가능
Condition: wait() & notify()의 문제점인 waiting pool 내 Thread를 구분하지 못한다는 점을 해결한 것
wait() & notify() ➡️ Condition의 await() & signal()
ReentrantLock: 재진입 가능한 Lock
특정 조건에서 Lock을 풀고, 나중에 다시 Lock을 얻어 임계영역으로 진입 가능
ReentrantReadWriteLock: 읽기 위한 Lock과 쓰기를 위한 Lock을 따로 제공함
StampedLock: ReentrantReadWriteLock에 낙관적인 Lock의 기능을 추가함