프로그램(HDD) -실행-> 프로세스(메모리)
스레드
프로세스 내에서 실제 작업을 수행
모든 프로세스는 하나 이상의 스레드를 가지고있다
프로세스 : 스레드 = 공장 : 일꾼
멀티 프로세스 & 멀티스레드
하나의 새로운 프로세스를 생성하는 것 보다
하나의 새로운 스레드를 생성하는 것이 더 적은 비용이듬
멀티스레드의 장단점
장점 | 단점 |
자원을 보다 효율적으로 사용할 수 있다 사용자에 대한 응답성이 향상된다 작업이 분리되어 코드가 간결해진다 "여러 모로 좋다" |
동기화에 주의해야 한다 (자원을 같이씀) 교착상태가 발생하지 않도록 주의해야 한다 각 스레드가 효율적으로 고르게 실행될 수 있게 해야한다 "프로그래밍 할 때 고려해야 할 사항들이 많다." |
스레드 구현과 실행
- Thread 클래스를 상속
run()을 오버라이딩(재정의) - Runnable 인터페이스를 구현
추상메서드 run()을 구현
public class ThreadTest01 {
public static void main(String[] args) {
// 싱글 스레드 프로그램
// 순서대로 처리됨
for(int i=1; i<=200; i++) {
System.out.print("*");
}
System.out.println();
System.out.println();
for(int i=1; i<=200;i++) {
System.out.print("$");
}
}
}
Thread를 사용하는 방법
방법1. Thread 상속 (extends)
- Thread클래스를 상속한 class를 작성한 후
- 이 class의 인스턴스를 생성한다.
- 생성된 인스턴스의 start()메서드를 호출해서 실행한다.
public class ThreadTest02 {
public static void main(String[] args) {
// 멀티 스레드 프로그램
// Thread를 사용하는 방법
// 방법1-2)
MyThread01 th1 = new MyThread01(); // 객체 생성
// 방법 1-3)
th1.start();
}
}
// 방법 1-1 ==> Thread클래스를 상속한 class를 작성한다
class MyThread01 extends Thread{
// 스레드가 처리할 내용을 run()메서드를 재정의해서 작성한다.
@Override
public void run() {
// 이 run()메서드 안에 이 스레드가 처리할 내용을 작성한다
for(int i=1; i<=200; i++) {
System.out.print("*");
}
}
}
방법2. Runnable 구현 (implement)
- Runnable인터페이스를 구현한 class를 작성한다.
- 이 class의 인스턴스를 생성한다.
- Thread클래스의 인스턴스를 생성한다.
(이 때 2번에서 생성한 인스턴스를 Thread클래스 생성자의 인수값으로 넣어서 생성한다) - 생성된 Thread클래스의 인스턴스의 start()메서드를 호출해서 실행한다.
public class ThreadTest02 {
public static void main(String[] args) {
// 멀티 스레드 프로그램
// Thread를 사용하는 방법
// 방법 2-2
MyRunner01 r = new MyRunner01();
// 방법 2-3
Thread th2 = new Thread(r);
// 방법2-4
th2.start();
}
}
// 방법2-1 ==> Runnable인터페이스를 구현한 class를 작성한다.
class MyRunner01 implements Runnable{
@Override
public void run() {
// 이 run()메서드 안에 이 스레드가 처리할 내용을 작성한다
for(int i=1; i<=200; i++) {
System.out.print("$");
}
}
}
방법3. 방법 2의 다른 방법 : 익명구현체
package kr.or.ddit.basic;
public class ThreadTest02 {
public static void main(String[] args) {
Runnable r2 = new Runnable() { // 객체를 생성함과 동시에 구현을 함
@Override
public void run() {
for(int i=1; i<=200; i++) {
System.out.print("@");
}
}
};
Thread th3 = new Thread(r2);
th3.start();
}
}
start() & run()
call stack하나 더 생성 > run이라는 메서드를 새로만든 call stack에 생성한 뒤 start가 사라짐
start()메서드는 스레드가 실행될 환경을 만들고 그곳에서 run이라는 자동으로 호출하게 함
Thread.sleep(시간)
주어진 시간동안 작업을 잠시 멈춘다
시간은 ms단위를 사용한다. 즉, 1000ms은 1초를 의미한다.
class MyThread01 extends Thread{
@Override
public void run() {
for(int i=1; i<=200; i++) {
System.out.print("*");
try {
// Thread.sleep(시간) 메서드
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
}
join()
현재의 위치에서 해당 스레드가 종료될 때까지 기다린다.
public class ThreadTest03 {
public static void main(String[] args) {
// 스레드가 수행되는 시간 체크해보기
// 1970년 1월 1일 0시 0분 0초 (표준시간)로 부터 경과한 시간을 ms(1/1000초)단위로 반환한다.
long startTime = System.currentTimeMillis();
// 처리할 내용...
Thread th = new Thread(new myRunner02());
th.start(); // 스레드 작업환경을 만들어주고 run을 호출해주기만함
// start 자체가 실행된 시간만 측정하기 때문에 올바른 방법이 아님
// join()을 써야 올바른 시간이 측정이 가능하다
try {
th.join(); // 현재의 위치에서 해당 스레드(현재는 변수 th에 저장된 스레드)가
// 종료될 때까지 기다린다.
} catch (InterruptedException e) {
// TODO: handle exception
}
long endTime = System.currentTimeMillis();
System.out.println("경과 시간 : "+(endTime-startTime));
}
}
class myRunner02 implements Runnable{
@Override
public void run() {
// 1부터 10억까지의 합계 구하기
long sum=0L;
for(long i=1L; i<=1_000_000_000L;i++) { // _ 숫자의 영향을 주지않음
sum+=i;
}
System.out.println("합계 : "+ sum);
}
}
단독 스레드 & 멀티 스레드
1 ~ 20억까지의 합계를 구하는 프로그램을 하나의 스레드가 단독으로 처리할 때와
여러개의 스레드가 협력해서 처리할 때 경과 시간을 비교해보기
public class ThreadTest04 {
public static void main(String[] args) {
// 단독으로 처리하는 스레드
SumThread sm = new SumThread(1L, 2_000_000_000L);
// 여럿이 협력해서 처리하는 스레드들
SumThread[] smArr = new SumThread[] { new SumThread(1L, 500_000_000L),
new SumThread(500_000_000L, 1_000_000_000L), new SumThread(1_000_000_000L, 1_500_000_000L),
new SumThread(1_500_000_000L, 2_000_000_000L), };
// 단독으로 처리하기...
long startTime = System.currentTimeMillis();
sm.start();
try {
sm.join();
} catch (InterruptedException e) {
// TODO: handle exception
}
long endTime = System.currentTimeMillis();
System.out.println("단독으로 처리할 때의 경과 시간 : " + (endTime - startTime));
// 단독으로 처리할 때의 경과 시간 : 597
// 여러 스레드가 협력해서 처리하기
startTime = System.currentTimeMillis();
for (int i = 0; i < smArr.length; i++) {
smArr[i].start();
}
for (SumThread s : smArr) {
try {
s.join();
} catch (InterruptedException e) {
// TODO: handle exception
}
}
endTime = System.currentTimeMillis();
System.out.println("협력해서 처리할 때의 경과 시간 : " + (endTime - startTime));
// 협력해서 처리할 때의 경과 시간 : 115
}
}
class SumThread extends Thread {
private long start;
private long end;
public SumThread(long start, long end) {
this.start = start;
this.end = end;
}
@Override
public void run() {
long sum = 0L;
for (long i = start; i <= end; i++) {
sum += i;
}
System.out.println(start + " 부터 " + end + "까지의 합계 : " + sum);
}
}
스레드 값 공유하여 다른 스레드에 영향을 미치게하는 방법
10초 안에 입력받는 프로그램 구현
받은 정보가 없을 때는 null
더보기
단독 스레드일 경우에는 각각의 행동으로 받아 프로그램을 구현할 수 없음
import javax.swing.JOptionPane;
public class ThreadTest05 {
public static void main(String[] args) {
// 사용자로부터 데이터 입력 받기
// String str = JOptionPane.showInputDialog("아무거나 입력하세요...");
// System.out.println("입력한 값 : "+str);
// 단독스레드와 비슷하기 때문에 시간제한동안 입력받는 작업은 불가능
// 멀티스레드 이용
for(int i=10; i>=1; i--) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO: handle exception
}
}
}
}
멀티 스레드로 static을 이용하는 방법을 사용하기
import javax.swing.JOptionPane;
public class ThreadTest06 {
public static void main(String[] args) {
Thread th1 = new DataInput();
Thread th2 = new MyCountDown();
th1.start();
th2.start();
}
}
// 데이터를 입력받는 스레드
class DataInput extends Thread{
public static boolean inputCheck = false;
@Override
public void run() {
String str = JOptionPane.showInputDialog("아무거나 입력하세요...");
inputCheck = true; // 입력이 완료되면 inputCheck를 true로 변경
System.out.println("입력한 값 : "+str);
}
}
//카운트 다운을 진행하는 스레드
class MyCountDown extends Thread{
@Override
public void run() {
for(int i=10; i>=1; i--) {
// 입력이 완료되었는 지 여부를 검사해서 입력이 완료되면 스레드 종료시킨다
if(DataInput.inputCheck) {
return;
}
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO: handle exception
}
}
System.out.println("10초가 지났습니다. 프로그램을 종료합니다..");
System.exit(0); // 프로그램 강제 종료
}
}
'JAVA > HIGH JAVA' 카테고리의 다른 글
[JAVA] 스레드 - 데몬스레드/상태/yield/종료 (0) | 2024.04.30 |
---|---|
4/29 Homework - 가위바위보 게임 (0) | 2024.04.29 |
[JAVA] 매개변수, 제네릭, enum (0) | 2024.04.26 |
4/25 Homework - 호텔관리 (0) | 2024.04.25 |
[JAVA] Properties (0) | 2024.04.25 |