멀티 태스킹
멀티 태스킹 (multi tasking) 두가지 이상의 작업을 동시에 처리한다.
멀티 프로세스 독립적으로 프로그램을 실행하고 여러 가지 자업 처리한다
멀티 스레드 한개의 프로그램을 실행하고 내부적으로 여러 가지작업처리한다.
메인(main) 스레드
모든 자바 프로그램은 메인 스레드가 main()메소드를 실행하며 시작된다.
메소드의 첫 코드부터 아래로 순차적으로 실행되고 종료는 마지막 코드가 실행되거나 return문을 만나면
종료
# java.awt.Toolkit 찾아보기. Toolkit.getDefaultToolkit(); ,
toolkit.beep(); # OO.start(); # Thread.sleep( ); # implements
Runnable = 쓰레드만들어주는것.
예시. 멀티
import java.awt.Toolkit;
public class BeepTask implements Runnable {
public void run() {
Toolkit toolkit = Toolkit.getDefaultToolkit();
for(int i=0; i<5; i++) {
toolkit.beep();
try {
Thread.sleep(500);
} catch(Exception e) {
}
}
}
}
import java.awt.Toolkit;
public class BeepTaskPrintExample {
public static void main(String[] args) {
// 멀티 스레드를 위한 선언.
Runnable beep = new BeepTask();
Thread thr = new Thread(beep);
thr.start(); // beeptask를 실행시키고
for(int i=0; i<5; i++) { // for문안에 있는 내용을 5번 반복한다.
System.out.println("띠링");
// 반복하는 소리를 듣기위해
try {
Thread.sleep(500);
} catch(Exception e) {
}
}
}
}
스레드의 이름
스레드는 자신의 이름을 가지고있다 일반적으로 이름을 설정하지 않을경우 Thread-n이라는 이름으로 설정되고 n은 번호를 말한다. 다른이름으로 설정을 원할경우 setName()을. 반대로 이름을 알고 싶을경우 getName()를 사용한다.
set와 getName는 Thread의 인스턴스 메소드 이므로 스레드 객체의 참조가 필요하다.
만일 스레드 객체의 참조를 가지고 있지 않다면 Thread의 정적 메소드인 currentThread()로 코드를 실행하는 현재 스레드이 참조를 얻을수 있다.
예시.
public class z_ThreadA extends Thread {
public z_ThreadA() {
setName("z_threada()");
}
public void run() {
for(int i=0; i<2; i++) {
System.out.println(getName() + " 가 출력한 내용");
}
}
}
public class z_ThreadB extends Thread {
public void run() {
for(int i=0; i<2; i++) {
System.out.println(getName() + " 가 출력한 내용");
}
}
}
public class z_ThreadNameExample { // 메인 스레드 이름 출력및 userthread 생성 및 시작
public static void main(String[] args) {
Thread main = Thread.currentThread(); // 이 코드를 실행하는 스레드 객체를 얻을거임
System.out.println("시작 스레드 이름: " + main.getName()); // 스레드 이름을 알고싶을경우 getName로 메소드 호출
z_ThreadA a = new z_ThreadA(); // z_threada는 이름을 변경했고.
System.out.println("작업스레드 이름: " + a.getName());
a.start();
z_ThreadB b = new z_ThreadB(); // z_threadb는 이름을 변경하지 않음. 이름을 변경하지 않으면 Thread-n으로 나온다
System.out.println("작업스레드 이름: " + b.getName());
b.start();
}
}
동시성과 병렬성
동시성 = 멀티 작업을 위해 하나의 코어에서 멀티 스레드가 번걸아 가며 실행됨
병렬성 = 멀티 작업을 위해 멀티 코어에서 개별스레드를 동시에 실행함
우선순위 방식 = 우선 순위가 높으면 스레드가 실행 상태를 더 많이 가지도록 스케줄링
1~10까지 값을 가질수 있고 기본은 5
순환 할당 방식(코드로 제어할수 없음) =시간 할당량(time slice)정해서 하나의 스레드를 정해진 시간만큼 실행
동기화 메소드와 동기화 블록
싱글 스레드 프로그램에서는 한개의 스레드가 객체를 독차지해서 사용하면 되지만 멀티 스레드 프로그램에서는 스레드 들이 객체를 공유해서 작업하는 경우가 있다 A, B의 스레드를 각각 2초간 정지하고 출력하면 마지막으로 사용된 스레드이 객체값이 출력되게되어 한스레드의 값은 무용지물이된다. 이를 방지하기 위해 동기화(synchronized)가 필요하다.
예시.
public class y_User1 extends Thread {
private y_Calculator calculator;
public void setCalculator(y_Calculator calculator) {
this.setName("User1");
this.calculator = calculator;
}
public void run() {
calculator.setMemory(100);
}
}
public class y_User2 extends Thread {
private y_Calculator calculator;
public void setCalculator(y_Calculator calculator) {
this.setName("User2");
this.calculator = calculator;
}
public void run() {
calculator.setMemory(10);
}
}
public class y_Calculator {
private int memory;
public int getMemory() {
return memory;
}
public /*synchronized*/ void setMemory(int memory) { // 공유 객체를 사용하고 싶지 않을땐 synchronized 를 사용한다.
// 그럼 스레드 값은 100 10으로 따로 따로 나온다.
this.memory = memory;
try {
Thread.sleep(2000); // 2초동안
} catch(InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + ": " + this.memory);
}
}
public class y_MainThreadExample {
public static void main(String[] args) {
y_Calculator Ca = new y_Calculator();
y_User1 user1 = new y_User1();
user1.setCalculator(Ca);
user1.start();
y_User2 user2 = new y_User2();
user2.setCalculator(Ca);
user2.start();
}
}
스레드 상태
스레드 객체를 생성하고 start() 메소드를 호출하면 곧바로 스레드가 실행되는 것처럼 보이지만
사실은 실행 대기 상태가 된다. 해당 상태를 아직 스케줄링이 되지 않아서 실행을 기다리고있는
상태를 말한다.
예시.
public class x_StatePrintThread extends Thread {
private Thread targetThread;
public x_StatePrintThread(Thread targetThread) {
this.targetThread = targetThread;
}
public void run() {
while(true) {
Thread.State state = targetThread.getState();
System.out.println("타깃 스레드 상태: " + state);
if(state == Thread.State.NEW) {
targetThread.start();
}
if(state == Thread.State.TERMINATED) {
break;
}
try {
Thread.sleep(500);
}catch(Exception e) {
}
}
}
}
public class x_TargetThread extends Thread {
public void run() {
for(long i=0; i<100000000; i++) {
}
try {
Thread.sleep(1500);
}catch(Exception e) {
for(long i=0; i<100000000; i++) {
}
}
}
}
public class x_ThreadStateExample {
public static void main(String[] args) {
x_StatePrintThread SPT = new x_StatePrintThread(new x_TargetThread());
SPT.start();
}
}
for문으로 저만큼 반복이 진행되고 이후 1.5초간 TIMED_WAITING상태로 돌아가며 다시 for문으로 반복시킨다.
스레드 상태제어
사용자는 미디어 플레이어 영상을 보다가 일시 정지도 가능하고 종료시킬수도 있다 일시정지는
조금 후 다시 동영상을 보겠다는것인데 플레이어는 동영상 스레드를 일시 정지 상태로 만들어서
사용자가 보는것도 정지되는것이다. 이런것이 스레드 상태제어라고 한다.
sleep() 주어진시간동안 정지를 하거나, 다른 스레드에게 실행을 양보 yield()하거나 다른 스레드의 종료 join()를 기다린다.
스레드 스케줄링은 어떤순위로 동시성으로 실행할것인가 결정한다.
스케줄링 의해 스레드들은 번갈아가며 run() 메소드를 조금씩 실행
일시정지 상태에는 WAITING, TIMED_WAITING, BLOCKED가 있다. 다시실행 상태로 가기 위해선
일시정지 상태에서 실행 대기상태(RUNNABLE)로 가야한다.
종료는 TERMINATED. 스레드의 객체 생성 상태는 NEW

예시. !STOP.
public class w_PrintThread1 extends Thread {
private boolean stop;
public void setStop(boolean stop) {
this.stop = stop;
}
public void run() {
while(!stop) {
System.out.println("실행");
}
System.out.println("정리");
System.out.println("종료");
}
}
public class w_StopFlagExample {
public static void main(String[] args) {
w_PrintThread1 printThread = new w_PrintThread1();
printThread.start();
try {
Thread.sleep(1000);
}catch(InterruptedException e) {
}
printThread.setStop(true);
}
}
데몬 스레드(daemon)
주 스레드의 작업 돕는 보조적인 역할 수행하는 스레드, 주 스레드가 데몬이 될 스레드의 setDaemon(true) 호출
반드시 start() 호출전 setDaemon(true)를 호출 그렇지 않으면 IIIegaIThreadStateException이 발생
실행중인 스레드가 데몬 스레드인지 구분은 isDaemon()메소드의 리턴값을 조사 true면 데몬 스레드
예시. 1초 주기로 save()메소드를 호출 3초가 되면 종료
public void save() {
System.out.println("저장");
}
@Override
public void run() {
while(true) {
try {
Thread.sleep(1000);
}catch(InterruptedException e) {
break;
}
save();
}
}
}
public class v_DaemonExample {
public static void main(String [] args) {
v_AutoSaveThread autosave = new v_AutoSaveThread();
autosave.setDaemon(true); // v_AutoSaveThread를 데몬 스레드로 만든다.
autosave.start();
try {
Thread.sleep(3000);
}catch(InterruptedException e) {
}
System.out.println("메인종료");
}
}
스레드 그룹은 관련된 스레드를 묶어서 관리할 목적으로 이용된다 JVM이 실행되면 system 스레드 그룹을 만든다
jvm에 운영에 필요한 스레드들을 생성해서 system 스레드 그룹에 포합시킨다 그리고 하위 system의 스레드 그룹으로 main을 만들고 메인 스레드를 main스레드 그룹에 포함시킴
#뭔 개소린지 모르겠음. 예시로 그냥 보자
Thread의 정적 메소드인 getAllStackTraces()를 이용하면 프로세스 내에서 실행하는 모든 스레드에 대한 정보를
얻을수있다. Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
getAllStackTraces() 메소드는 Map 타입의 객체를 리턴하는데 키는 스레드 객체이고 값은 스레드의 상태 기록들을 갖고있는 StackTraceElement[] 배열이다
예시. 스레드의 이름가 데몬스레드 여부 그리고 속한 스레드 그룹 이름을 출력
public class u_AutoSaveThread extends Thread {
public void save() {
System.out.println("저장.");
}
@Override
public void run() {
while(true) {
try { Thread.sleep(1000);
}catch(InterruptedException e) {
break;
}
save();
}
}
import java.util.Map;
import java.util.Set;
public class u_ThreadInfoExample {
public static void main(String[] args) {
u_AutoSaveThread AST = new u_AutoSaveThread();
AST.setName("u_AutoSaveThread");
AST.setDaemon(true);
AST.start();
Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces(); // 프로세스에서
Set<Thread> threads = map.keySet(); // 실행하는 모든 Thread를 가져오는 코드
for(Thread thread : threads) { // thread를 하나씩 가져와 루핑시킨다
System.out.println("name: " + thread.getName() +
((thread.isDaemon())?"(데몬)": "(주)"));
System.out.println("\t" + "소속그룹: " + thread.getThreadGroup().getName());
System.out.println();
}
}
}
'Java > Java' 카테고리의 다른 글
자바[Java] 컬렉션 프레임워크(Collection Framework)에 대한 개념정리 (0) | 2021.10.25 |
---|---|
Java Generic 제네릭 (0) | 2021.10.25 |
Java 기본 API 클래스 #3 (0) | 2021.10.21 |
Java 기본API클래스 #2 (0) | 2021.10.20 |
Java 기본API클래스 #1 (0) | 2021.10.20 |