728x90
sleep()
- 현재 쓰레드(자기 자신, static)를 지정된 시간동안 멈추게 함.
static void sleep(long millis[, int nanos]) //천분의 일초(+나노초) 단위
- 예외처리를 해야함(InterruptedException(Exception의 자손)이 발생하면 깨어남)
try{
Thread.sleep(1000); //쓰레드를 1초동안 멈추게 함
} catch(InterruptedException e){}
//항상 try-catch를 하기 번거로움
//=>
void delay(long millis){
try{
Thread.sleep(millis);
} catch(InterruptedException e){}
}
- 특정 쓰레드를 지정해서 멈추게 하는 것은 불가능함
try{
th1.sleep(1000);
} catch(InterruptedException e){}
=>
try{
Thread.sleep(1000); //클래스 이름(static 메소드)
} catch(InterruptedException e){}
package chapter13;
class 쓰레드6_1a extends Thread{
public void run() {
for(int i = 0; i < 300; i++) System.out.print("-");
System.out.println("<<th1>>종료");
}
}
class 쓰레드6_1b extends Thread{
public void run() {
for(int i = 0; i < 300; i++) System.out.print("|");
System.out.println("[[th2]]종료");
}
}
public class 쓰레드6_1 {
public static void main(String[] args) {
쓰레드6_1a th1 = new 쓰레드6_1a();
쓰레드6_1b th2 = new 쓰레드6_1b();
th1.start();
th2.start();
// try {
//// th1.sleep(2000); //th1이 잠자는 것이 아닌 main 쓰레드가 잠자기
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// }
delay(2000);
System.out.println("((main))종료");
}
static void delay(long millis) {
try {
// th1.sleep(2000); //th1이 잠자는 것이 아닌 main 쓰레드가 잠자기
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
}
interrupt()
- 대기상태(WAITING)인(작업이 중단된) 쓰레드를 실행대기 상태(RUNNABLE)로 만듦
void interrupt() //쓰레드의 interrupted상태를 false에서 true로 변경
boolean isInterrupted() //쓰레드의 interrupted상태를 반환
static boolean interrupted() //현재 쓰레드의 interrupted상태를 알려주고, false로 초기화
package chapter13;
import javax.swing.JOptionPane;
class Thread6_2 extends Thread{
public void run() {
int i = 10;
while(i!=0 && !isInterrupted()) {
System.out.println(i--);
for(long x=0;x<250000000000L;x++); //시간지연
}
System.out.println("카운트가 종료됨");
System.out.println("th1의 isInterrupted() : " + this.isInterrupted());
System.out.println("th1의 interrupted() : " + Thread.interrupted()); //isInterrupted()와 달리 interrupted()는 interrupted라는 상태변수를 false로 초기화
System.out.println("th1의 interrupted() : " + Thread.interrupted());
}
}
public class 쓰레드6_2 {
public static void main(String[] args) {
Thread6_2 th1 = new Thread6_2();
th1.start();
System.out.println("isInterrupted() : " + th1.isInterrupted());
String input = JOptionPane.showInputDialog("아무 값이나 입력");
System.out.println("입력한 값은 " + input);
th1.interrupt(); //interrupt()를 호출하면 interrupted상태가 true가 됨
System.out.println("isInterrupted() : " + th1.isInterrupted());
System.out.println("main 쓰레드의 interrupted() : " + Thread.interrupted()); //main쓰레드가 interrupt되었는지 확인
}
}
suspend(), resume(), stop()
- 쓰레드의 실행을 일시정지시킴
- 쓰레드의 실행을 재개시킴
- 쓰레드의 실행을 완전정지시킴
void suspend() //쓰레드를 일시정지 시킴
void resume() //suspend()에 의해 일시정지된 쓰레드를 실행대기상태로 만듦
void stop() //쓰레드를 즉시 종료시킴
- suspend(), resume(), stop()은 교착상태에 빠지기 쉬워 deprecated됨.
사용을 권장하지 않음
class Ex implements Runnable{
boolean suspended = false; //일시정지
boolean stopped = false; //정지
public void run(){
while(!stopped){
if(!suspended){
/* 쓰레드가 수행할 코드 */
}
}
}
public void suspend(){suspended = true;}
public void resume(){suspended = false;}
public void stop(){stopped = true;}
}
package chapter13;
class RunImplEx1 implements Runnable{
@Override
public void run() {
while(true) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
public class 쓰레드7_1 {
public static void main(String[] args) {
RunImplEx1 r = new RunImplEx1();
Thread th1 = new Thread(r,"*");
Thread th2 = new Thread(r,"**");
Thread th3 = new Thread(r,"***");
th1.start();
th2.start();
th3.start();
try {
Thread.sleep(2000);
th1.suspend(); //쓰레드 th1을 잠시 중단
Thread.sleep(2000);
th2.suspend();
Thread.sleep(3000);
th1.resume(); //쓰레드 th1을 재개
Thread.sleep(3000);
th1.stop(); //쓰레드 th1을 강제종료
th2.stop();
Thread.sleep(2000);
th3.stop();
} catch (InterruptedException e) {
}
}
}
package chapter13;
class MyThread7_1 implements Runnable{
volatile boolean suspended = false; //volatile 변수값이 쉽게 바뀜. 복사본 사용X
volatile boolean stopped = false;
Thread th;
MyThread7_1(String name){
th = new Thread(this, name); //Thread(Runnable r, String name)
}
void start() {
th.start();
}
void stop() {
stopped = true;
}
void suspend() {
suspended = true;
}
void resume() {
suspended = false;
}
@Override
public void run() {
while(!stopped) {
if(!suspended) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
}
public class 쓰레드7_1 {
public static void main(String[] args) {
MyThread7_1 th1 = new MyThread7_1("*");
MyThread7_1 th2 = new MyThread7_1("**");
MyThread7_1 th3 = new MyThread7_1("***");
th1.start();
th2.start();
th3.start();
try {
Thread.sleep(2000);
th1.suspend(); //쓰레드 th1을 잠시 중단
Thread.sleep(2000);
th2.suspend();
Thread.sleep(3000);
th1.resume(); //쓰레드 th1을 재개
Thread.sleep(3000);
th1.stop(); //쓰레드 th1을 강제종료
th2.stop();
Thread.sleep(2000);
th3.stop();
} catch (InterruptedException e) {
}
}
}
join()
- 지정된 시간동안 특정 쓰레드가 작업하는 것을 기다림
void join() //작업이 모두 끝날때까지 기다림
void join(long millis) //천분의 일초 동안
void join(long millis, int nanos) //천분의 일초 + 나노초 동안
- 예외처리를 해야함(InterruptedException이 발생하면 작업 재개)
package chapter13;
class Thread8_1a extends Thread{
public void run() {
for(int i = 0; i < 300; i++) {
System.out.print(new String("-"));
}
}
}
class Thread8_1b extends Thread{
public void run() {
for(int i = 0; i < 300; i++) {
System.out.print(new String("|"));
}
}
}
public class 쓰레드8_1 {
static long startTime = 0;
public static void main(String[] args) {
Thread8_1a th1 = new Thread8_1a();
Thread8_1b th2 = new Thread8_1b();
th1.start();
th2.start();
startTime = System.currentTimeMillis(); //시작시간
try {
th1.join(); //main쓰레드가 th1의 작업이 끝날때까지 기다림
th2.join(); //main쓰레드가 th2의 작업이 끝날때까지 기다림
} catch (InterruptedException e) {
}
System.out.println("소요시간 : " + (System.currentTimeMillis()-startTime));
}
}
yield()
- 남은 시간을 다음 쓰레드에게 양보고하고, 자신(현재 쓰레드)은 실행대기함
- yield()와 interrupt()를 적절히 사용하면, 응답성과 효율을 높일 수 있음
쓰레드의 동기화(synchronization)
- 멀티 쓰레드 프로세스에서는 다른 쓰레드의 작업에 영향을 미칠 수 있음
- 진행중인 작업이 다른 쓰레드에게 간섭받지 않게 하려면 '동기화'가 필요
※쓰레드의 동기화 : 한 쓰레드가 진행중인 다른 작업을 다른 쓰레드가 간섭하지 못하게 막는 것 - 동기화하려면 간섭받지 않아야 하는 문장들을 '임계 영역'으로 설정
- 임계영역은 락(lock)을 얻은 단 하나의 쓰레드만 출입가능(객체 1개에 락 1개)
synchronized를 이용한 동기화
- synchronized로 임계영역(lock이 걸리는 영역)을 설정하는 방법
1. 메소드 전체를 임계 영역으로 지정(개수 최소화 영역 최소화)
2. 특정한 영역을 임계 영역으로 지정
//1. 메소드 전체를 임계영역으로 지정
public synchronized void sum(){
//....
}
//2. 특정 영역을 임계영역으로 지정
synchronized(객체의 참조변수){
//....
}
package chapter13;
class Account{
private int balance = 1000; //private으로 해야 동기화가 의미가 있음
public synchronized int getBalance() {
return balance;
}
// public void withdraw(int money) {
public synchronized void withdraw(int money) { //synchronized로 메소드를 동기화
if(balance>=money) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
balance-=money;
}
}
}
class Runnable9_1 implements Runnable{
Account account = new Account();
public void run() {
while(account.getBalance()>0) {
//100,200,300 중 한 값을 임의로 선택해서 출금
int money = (int)(Math.random()*3+1)*100;
account.withdraw(money);
System.out.println("balance : " + account.getBalance());
}
}
}
public class 쓰레드9_1 {
public static void main(String[] args) {
Runnable r = new Runnable9_1();
new Thread(r).start(); //ThreadGroup에 의해 참조되므로 gc대상이 아님
new Thread(r).start(); //ThreadGroup에 의해 참조되므로 gc대상이 아님
}
}
wait()와 notify()
- 동기화의 효율을 높이기 위해 wait(), notify()를 사용
wait() 기다리기, notify() 통보, 알려주기 - Object클래스에 정의되어 있으며, 동기화 블록 내에서만 사용할 수 있음
wait() : 객체의 lock을 풀고 쓰레드를 해당 객체의 waiting pool에 넣음
notify() : waiting pool에서 대기중인 쓰레드 중의 하나를 깨움(귓속말)
notifyAll() : waiting pool에서 대기중인 모든 쓰레드를 깨움(방송)
728x90