Thread의 생명주기
Thread 자신이 하던 작업을 잠시 멈추고 다른 Thread가 지정된 시간동안 작업을 수행하도록 할 때 사용한다.
join()
join(time)
code로 알아보아요 ~
package lecture0715;
class ThreadEx_07_1 extends Thread {
@Override
public void run() {
for(int i=0; i<300; i++) {
System.out.print("-");
}
}
}
class ThreadEx_07_2 extends Thread {
@Override
public void run() {
for(int i=0; i<300; i++) {
System.out.print("|");
}
}
}
public class ThreadExam07 {
public static void main(String[] args) {
Thread t1 = new ThreadEx_07_1();
Thread t2 = new ThreadEx_07_2();
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (Exception e) {
// TODO: handle exception
}
System.out.println("<<main>> 종료 ");
}
}
package lecture0715;
class ThreadEx_08_1 extends Thread {
final static int MAX_MEMORY = 1000; // 내가 사용할 수 있는 메모리의 총량
int usedMemory = 0;
@Override
public void run() {
while(true) {
try {
Thread.sleep(10000); // 10초 동안 자요!
} catch (Exception e) {
System.out.println("interrupt()에 의해서 깨어났어요!");
}
gc();
System.out.println("메모리 청소 완료! 현재 사용 메모리 량 : " + freeMemory() );
}
}
public void gc() {
usedMemory -= 300;
if(usedMemory < 0) {
usedMemory = 0;
}
}
public int totalMemory() { return MAX_MEMORY; }
public int freeMemory() { return MAX_MEMORY - usedMemory; }
}
public class ThreadExam08 {
public static void main(String[] args) {
ThreadEx_08_1 t = new ThreadEx_08_1();
t.setDaemon(true);
t.start();
int requiredMemory = 0;
for(int i=0; i<20; i++) {
requiredMemory = ((int)(Math.random() * 10)) * 20; // 0.0보다 같거나 크고 10보다 작은 정수
// 필요한 memory가 사용할 수 있는 양보다 크거나
// 현재 전체 메모리양의 60% 이상을 사용하고 있을 때 gc를 실행
if((requiredMemory > t.freeMemory()) || (t.freeMemory() < t.totalMemory() * 0.4)) {
t.interrupt(); // gc()실행이 끝날때까지 기다리지 않아요!
try {
t.join();
} catch (Exception e) {
// TODO: handle exception
}
}
t.usedMemory += requiredMemory;
System.out.println("사용된 메모리 량 : " +t.usedMemory);
}
}
}
Java에서 “Lock”을 얻어 임계영역을 설정하려면
⇒ synchronized
keyword
package lecture0715;
// Thread에 의해서 공유되는 공유객체를 생성하기 위한 class
class Account {
private int balance = 1000; // 계좌 잔액
public int getBalance() {
return balance;
}
// 출금하는 method
public void withdraw(int money) {
if(balance >= money) {
try {
**Thread.sleep(1000)**; // 하나의 thread가 자고 있는 동안 다른 thread가 들어오게 된다.
} catch (Exception e) {
// TODO: handle exception
}
balance -= money;
}
}
}
class ThreadEx_09 implements Runnable {
Account acc = new Account(); // 공용 객체
@Override
public void run() {
while(acc.getBalance() > 0) {
int money = ((int) (Math.random() * 3 + 1) * 100);
acc.withdraw(money);
System.out.println("남은 잔액은 : " + acc.getBalance());
}
}
}
public class ThreadExam09 {
public static void main(String[] args) {
ThreadEx_09 r = new ThreadEx_09(); // runnable 객체
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}
/* 출력 */
남은 잔액은 : 900
남은 잔액은 : 900
남은 잔액은 : 600
남은 잔액은 : 500
남은 잔액은 : 200
남은 잔액은 : 200
남은 잔액은 : 0
남은 잔액은 : -200
// 실행시켜보면 출력이 따닥따닥 떨어지는 것이 보인다. -> 두개의 thread가 동시에 실행
// 하나의 thread가 자고 있는 동안 다른 thread가 들어와서 수행되므로 잔액이 음수가 찍히게 된다.
해결법 1. method 동기화
package lecture0715;
// Thread에 의해서 공유되는 공유객체를 생성하기 위한 class
class Account {
private int balance = 1000; // 계좌 잔액
public int getBalance() {
return balance;
}
// 출금하는 method => 동기화 처리
public **synchronized** void withdraw(int money) { // 먼저 들어온 thread가 lock을 얻게된다. -> thread가 순차처리됨.
if(balance >= money) {
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
}
balance -= money;
}
}
}
class ThreadEx_09 implements Runnable {
Account acc = new Account(); // 공용 객체
@Override
public void run() {
while(acc.getBalance() > 0) {
int money = ((int) (Math.random() * 3 + 1) * 100);
acc.withdraw(money);
System.out.println("남은 잔액은 : " + acc.getBalance());
}
}
}
public class ThreadExam09 {
public static void main(String[] args) {
ThreadEx_09 r = new ThreadEx_09(); // runnable 객체
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}
/* 출력 */
남은 잔액은 : 800
남은 잔액은 : 500
남은 잔액은 : 200
남은 잔액은 : 200
남은 잔액은 : 200
남은 잔액은 : 100
남은 잔액은 : 100
남은 잔액은 : 0
남은 잔액은 : 0
// 실행시켜보면 하나씩 딱딱 떨어지는 것을 알 수 있다. -> thread가 순차적으로 실행
해결법2. 동기화 block을 생성 🌟
package lecture0715;
// Thread에 의해서 공유되는 공유객체를 생성하기 위한 class
class Account {
private int balance = 1000; // 계좌 잔액
public int getBalance() {
return balance;
}
// 출금하는 method => 동기화 처리
public void withdraw(int money) {
**// 동기화 블럭**
**synchronized (this) {
if(balance >= money) {
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
}
balance -= money;
}**
}
}
}
class ThreadEx_09 implements Runnable {
Account acc = new Account(); // 공용 객체
@Override
public void run() {
while(acc.getBalance() > 0) {
int money = ((int) (Math.random() * 3 + 1) * 100);
acc.withdraw(money);
System.out.println("남은 잔액은 : " + acc.getBalance());
}
}
}
public class ThreadExam09 {
public static void main(String[] args) {
ThreadEx_09 r = new ThreadEx_09(); // runnable 객체
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}
/* 출력 */
남은 잔액은 : 900
남은 잔액은 : 700
남은 잔액은 : 400
남은 잔액은 : 300
남은 잔액은 : 0
남은 잔액은 : 0
syncronized
를 이용해서 공유데이터를 보존한다. Thread가 공유자원에 대한 LOCK
을 획득한 후 오랜 시간을 보낸다!
→ 문제가 발생한다.
wait()
→ LOCK을 놓고 대기notify()
→ 대기상태에 있는 Thread가 실행할 수 있도록 block을 해제동기화 keyword
연습문제 풀어보기
1. “1초마다 자신의 이름을 출력하는 Thread를 2개 생성” 이름을 출력할 때 교대로 출력하는걸 보장하는 코드를 작성해보아요!
2. Thread가 3개 이상일 때 순서대로 출력
3. [1번 2번 출력] → 1초 뒤 → [1번 2번 출력] → 1초 뒤 → [1번 2번 출력] → 1초 뒤 → .. 나오게 하기
Java IO
java.io
package로 제공표준입력 → keyboard
표준출력 → monitor
🌟 Stream instance
Java에서 특정 장치에서 data를 읽거나 특정장치로 data를 보낼 때 사용하는 매개 객체
→Java program과 File/monitor/keyboard/.. 간의 중간 다리 역할(통로)을 한다.
Stream 객체의 특징
단방향
FIFO 구조
Stream 구분
Object Stream을 통해서 객체(instance)도 전달할 수 있어요.
단, 모든 객체가 다 되는건 아니에요!!
⇒ 만약 instance를 생성한 class가 Serializable interface를 구현하고 있으면 가능!!