MusicPlayer 3명은 MusicBox를 사용한다.
이는 하나의 객체를 여러 개의 스레드가 사용함을 의미한다.
public class MusicBox {
public void playMusicA() {
for (int i = 0; i < 10; i++) {
System.out.println("드레이크 음악!");
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void playMusicB() {
for (int i = 0; i < 10; i++) {
System.out.println("켄트릭 라마 음악!");
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void playMusicC() {
for (int i = 0; i < 10; i++) {
System.out.println("제이지 음악!");
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class MusicPlayer extends Thread{
int type;
MusicBox musicBox;
public MusicPlayer(int type, MusicBox musicBox) {
this.type = type;
this.musicBox = musicBox;
}
@Override
public void run() {
switch (type) {
case 1:
musicBox.playMusicA();
break;
case 2:
musicBox.playMusicB();
break;
case 3:
musicBox.playMusicC();
break;
}
}
}
public class MusicBoxExam {
public static void main(String[] args) {
MusicBox box = new MusicBox();
MusicPlayer kang = new MusicPlayer(1, box);
MusicPlayer kim = new MusicPlayer(2, box);
MusicPlayer yang = new MusicPlayer(3, box);
kang.start();
kim.start();
yang.start();
}
}
해당 메서드 앞에 리턴 타입으로 "synchronized"를 추가한다.
먼저 호출된 메서드에 synchronized 키워드가 있을 경우, 객체의 사용권을 가지며 synchronized가 붙은 다른 쓰레드들은 대기 상태에 놓인다.
참고로 synchronized를 붙이지 않은 메서드는 대기 상태가 아닌, 제멋대로 실행된다.
public class MyThred1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("MyThred1 : " + i);
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
MyThred1 thread = new MyThred1();
// Thread 시작
thread.start();
System.out.println("기다리는 중....");
try {
// 대기
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 종료");
}
}
public class ThreadB extends Thread {
int total;
@Override
public void run() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
System.out.println(i + "를 더하다");
total += i;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
notify();
}
}
}
public class ThreadA {
public static void main(String[] args) {
ThreadB threadB = new ThreadB();
threadB.start();
synchronized (threadB) {
try {
System.out.println("threadB 완료까지 대기");
threadB.wait(); // notify() 메서드를 만나야 깨어난다.
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("total : " + threadB.total);
}
}
}
데몬 : 리눅스, 유닉스 계열의 운영체제에서 백그라운드로 동작하는 프로그램
데몬 쓰레드 : 자바에서 데몬과 유사하게 동작하는 쓰레드
public class DaemonThread implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("데몬쓰레드 실행 중");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
break; // 에러 발생 시 탈출을 위함
}
}
}
public static void main(String[] args) {
Thread thread = new Thread(new DaemonThread());
thread.setDaemon(true); // 쓰레드를 데몬쓰레드로 만들기 위한 설정
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("메인 쓰레드 종료");
}
}