프로그램(ex) 계산기)을 실행하고 실행되고 있는 상태를 프로세스라고 표현한다
프로세스의 자원을 이용해서 작업을 수햇하는 것을 쓰레드 라고한다
하나의 프로세스는 복수의 쓰레드를 가질 수 있다.
따로 처리하지 않으면 일반적으로 하나의 프로세스는 하나의 쓰레드를 갖는다
쓰레드 작성
class 클래스이름 extends Thread{
public void run(){
동시다발로 동작시키고자 하는 내용
}
Thread를 확장하여 새로운 클래스를 만들고
run메소드를 오버라이딩하여
동시다발로 동작시키고자 하는 내용을 써 준다.
public class CleanThread extends Thread{
public void run() {
System.out.println("직원 청소 시작 Thread");
for (int i = 2; i <= 10; i += 2) {
System.out.println(i + "번방 청소중 Thread");
}
System.out.println("직원 청소 끝 Thread");
}
}
public class _01_Thread {
public static void main(String[] args) {
// 쓰레드 생성
CleanThread cleanThread = new CleanThread();
// run 메소드를 직접 호출해서 Thread안에있는 run 메소드를 수행하는것 뿐이다
// cleanThread.run();
cleanThread.start();
cleanByBoss();
}
public static void cleanByBoss() {
System.out.println("사장 청소 시작");
for (int i = 1; i <= 10; i += 2) {
System.out.println(i + "번방 사장 청소중");
}
System.out.println("사장 청소 끝");
}
}
출력문이 차례대로 나오지 않고 섞었다. - 쓰레드를 사용했기때문에 동시에 여러일을 처리함
public class CleanRunnable implements Runnable{
@Override
public void run() {
System.out.println("직원 청소 시작 Runnable");
for (int i = 2; i <= 10; i += 2) {
System.out.println(i + "번방 청소중 Runnable");
try {
// 지정한 시간만큼 정지한다
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("직원 청소 끝 Runnable");
}
public class _02_Runnable {
public static void main(String[] args) {
CleanRunnable cleanRunnable = new CleanRunnable();
Thread thread = new Thread(cleanRunnable);
thread.start();
cleanByBoss();
}
public static void cleanByBoss() {
System.out.println("사장 청소 시작");
for (int i = 1; i <= 10; i += 2) {
System.out.println(i + "번방 사장 청소중");
}
System.out.println("사장 청소 끝");
}
}
thread를 상속할 때와 비슷한 기능을 한다
public class _03_Join {
public static void main(String[] args) {
CleanRunnable cleanRunnable = new CleanRunnable();
Thread thread = new Thread(cleanRunnable);
thread.start();
try {
// join은 이 코드가 끝날때까지 기다렸다가 다음으로 넘어간다
thread.join(2500); // 2.5초 대기
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
cleanByBoss();
}
public static void cleanByBoss() {
System.out.println("사장 청소 시작");
for (int i = 1; i <= 10; i += 2) {
System.out.println(i + "번방 사장 청소중");
try {
// 지정한 시간만큼 정지한다
Thread.sleep(1000); // 1초 대기
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("사장 청소 끝");
}
}
결과
만약, 두개 이상의 객체를 가능하면 공평하게(동시다발) 실행 되게끔 즉, 한번에 여러개의 메소드가 동시에 실행되는 것을 "멀티 쓰레드"라고 하고 이것을 위하여 자바에서는 Thread 클래스와 Runnable 인터페이스를 이용한다
자바에서는 멀티쓰레드 프로그래밍을 위하여 Thread라는 클래스와 Runnable이라는
인터페이스를 이용한다.
Thread를 가동시키면가능하면 공평하게 실행이 되게끔 스케줄링 해준다.
그러나, 만약 응급성이 있는 객체라면 가능하면 다른 객체들 보다 더 빨리 작업을 수행하도록
우선순위를 설정 할 수 있다
setPriority(newPriority);
class Person extends Thread{
String name;
public Person(String name) {
this.name = name;
}
public void run() {
for(int i=1; i<=10; i++) {
System.out.println(name+"가(이) 밥을 먹어요~");
try {
Thread.sleep(100);
}catch (Exception e) {
// TODO: handle exception
}
}
}
public class ThreadTest {
public static void main(String[] args) {
Person p1 = new Person("이문관");
Person p2 = new Person("김지훈");
Person p3 = new Person("김범진");
//최고 우선순위를 설정
// p1.setPriority(10);
p1.setPriority(Thread.MAX_PRIORITY);
p1.start();
p2.start();
p3.start();
}
}
우선순위를 설정했더라도 항상 먼저 끝내는 것이 아니다
public class Room {
public int number = 1;
public void clean(String name) {
System.out.println(name + " : " + number + "번방 청소 중");
number++;
}
}
public class _05_Synchronization {
public static void main(String[] args) {
// 동기화
// 여러 쓰레드에서 하나의 변수에 접근해서 업데이트하면 중복될 수 있다
// 다른 쓰레드에서 오류가나도 다른 쓰레드도 문제가 있는게 아니다
Room room = new Room();
Runnable cleaner1 = new Runnable() {
@Override
public void run() {
System.out.println("직원1 청소 시작");
for (int i = 1; i <= 5; i++) {
room.clean("직원1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("직원1 청소 끝");
}
};
Runnable cleaner2 = () -> {
System.out.println("직원2 청소 시작");
for (int i = 1; i <= 5; i++) {
room.clean("직원2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("직원2 청소 끝");
};
Thread cleaner1Thread = new Thread(cleaner1);
Thread cleaner2Thread = new Thread(cleaner2);
cleaner1Thread.start();
cleaner2Thread.start();
}
}
1번방부터 10번방 까지 차례대로 청소하는 메시지를 출력하고 싶은데 멀티 쓰레드를 사용하니까
동시에 하나의 clean메소드에 접근해서 일부 방번호가 겹치게된다
이러한 문제를 해결하기 위해서 동기화가 필요하다
public class Room {
public int number = 1;
// synchronized 를 추가하면 동기화
synchronized public void clean(String name) {
System.out.println(name + " : " + number + "번방 청소 중");
number++;
}
}
synchronized를 붙이면 이미 누군가 이 메소드를 사용중이라면 다른 사람은 이 메소드가 끝날때까지 접근이 불가능하다
쓰레드사이의 통신
- 두개 이상의 쓰레드를 가동시키면 가능하면 공평하게 실행된다 반드시 1 : 1로 동작하게 하려면 쓰레드사이에 통신을 이용할 수 있다
- 임계영역에 힌번에 하나의 쓰레드만 접근할 수 있으므로 다른 쓰레드가 일을 마칠때까지 대기하고 있다가 그 쓰레드가 일이 끝나면 대기중인 쓰레드를 깨워주고 하기 위해서는 쓰레드 사이에 통신이 필요하다
- 쓰레드의 통신을 위하여 Object클래스의 wait과 notify를 이용한다
wait
참고
나도코딩 유튜브