◐쓰레드(520p)
◐
람다식
파일입출력
프로세스 : 실행중에 있는, 메모리에서 올라와져 있는 로딩된 프로그램
프로세서와 프로세스는 다르다
1. program : C드라이브에 설치된 소프트웨어
process : 실행 중인 프로그램, 메모리에 로딩된 프로그램
하나 - single process, 두개이상 - Multi process
프로세스는 적어도 하나의 스레드를 가진다.
(프로세스는 cpu를 사용하는 최소단위)
cpu는 쓰레드랑 소통한다.
processor : 프로세서(processor)는 프로세스를 실행하는 주체이다.
Thread : 하나의 실행 흐름으로 프로세스 내부에 존재
2. 쓰레드의 동시성(concurrency)과 병렬성(parallelism)
-단일 thread로 2개의 작업을 처리할 때 각 작업은 순차적으로 처리됨
먼저 작업이 완전히 종료된 이후에 두 번째 작업이 실행되는 것
-multi thread : 동시성과 병렬성을 가지고 있음
동시성과 병렬성을 활용해 여러 작업을 동시에 실행하거나
동시에 실행되는 것 처럼 보이게 하는 것
1) 동시성 (concurrency)
- 처리할 수 작업의 수가 cpu의 코어 수보다 많을 때 : cpu는 각 작업 쓰레드의 요청 작업을 번갈아가면서 실행
매우 짧은 간격으로 교차 실행하기 때문에 사용자는 두 작업이 마치 동시에 실행되는 것 처럼 보이는 것(시분할 처리) - 실제는 시간단위로 쪼개서 나눠서 작업하는 것을 매우빠르게 처리한다. 그런데, 이것이 너무빨리해서 마치 동시에 처리하는 것처럼 보인다.
2) 병렬성(parallelism)
- 처리할 작업의 수보다 cpu의 코어 수가 더 많을 때 : 각각의 작업을 각각의 코어에 할당해 동시에 시행할 수 있기 때문에
동시에 작업이 수행됨
자바는
자바는 main메소드 이전에 메인 쓰레드를 먼저 실행한다.
3. Thread 생성 및 실행
- 방법1 : Thread Class를 상속받아 run() 메소드를 재정의(overriding)
(방법1은 extends는 하나밖에 안되기떄문에 여러개를 상속해야 되는 경우는,
방법2 Runnable interface로 구현한다)
- 방법2 : Runnable interface 구현 -> 추상메소드인 run() 구현 => Thread 생성자로 Runnable 객체 전당
- java가 이렇게 쓰레드 생성에 두 가지 방법으로 사용하는 이유는 단일 상속을 지원하기 때문
다른 클래스를 이미 상속 받고 있다면 Thread 클래스를 상속받을 수 없기 때문에 쓰레드를 생성할 수 없음
1) 방법 1 : Thread class를 상속받아 run()메소드 재정의(overriding)
* 방법 1 Thread class를 상속받아 run()메서드 재정의
1-1) 클래스 정의 : 쓰레드 클래스를 상속받아 run() 메소드를 재정의(overriding)한
클래스 또는 익명 이너 클래스로 정의>
class MyThread extends Thread{
@Override
public void run(){
쓰레드 작업 내용
}
}
1-2) 객체 생성 : Thread 객체 생성 >
Thread myThread = new MyThread();
또는
MyThread myThread = new MyThread();
1-3) 쓰레드 실행 : start() 메소드를 이용해 쓰레드 실행 >
myThread.start(); // 멀티쓰레드
// myThread.run(); // run()을 호출해도 오류는 없지만 단일 쓰레드로 동작
쓰레드는 단 한번만 호출할 수 있다. 다시 실행못합니다.
1개의 쓰레드에 대해서는 start()메소드 한번만 가능하다.
다시 호출 되면 예외가 발생(IllegalThreadStateException이란
예외 발생)
myThread.start(); // 불가능
myThread.start(); // 불가능
2번 쓰레드를 돌리고 싶으면, 객체를 다시 생성해야합니다.
- start() : 새로운 쓰레드 생성/추가하기 위한 모든 준비 + 새로운 쓰레드 위에 run() 실행
- 쓰레드의 내부에 run()메서드가 있기 때문에 run()을 직접 호출해도 오류는 발생하지 않음
다만 이때 별도의 쓰레드가 아닌 현재의 쓰레드에서 일반 메서드처럼 실행됨
2)방법2 : Runnable interface 구현
Runnable interface 구현(추상메서드(run()) 구현)
=> Thread 생성자로 Runnable 객체 전달
2-1) 클래스 정의 : Runnable 인터페이스를 구현한 클래스 정의
추상메서드 run() 구현
class MyRunnable implements Runnable{
@Override
public void run(){
쓰레드 작업 내용
}
}
2-2) 객체 생성 : Runnable 객체 생성 -> Thread 객체 생성(생성자에 Runnable 객체 전달)
Runnable runable = new MyRunnable();
또는
MyRunnable r = new MyRunnable();
// Runnable은 함수적 인터페이스(추상메소드 하나만 가진 인터페이스)로 내부에 start()메소드 없어 오류 발생 따라서 Thread 객체 필요
// Thread 생성자의 매개변수로 전달
Thread myThread = new Thread(r);
2-3) 쓰레드 실행 : start()메서드를 이용해 쓰레드 실행
myThread.start();
3) 방법3 :
new Thread(){
public void run(){
}
}.start()
4. 데몬 쓰레드(daemon thread)
일반적으로 쓰레드는 독립적으로 수행되기 때문에 메인 쓰레드를 종료해도
작업 쓰레드는 계속 실행됨
(어떤 쓰레드는 다른 쓰레드의 보조작업을 수행하기 때문에(한글문서작업(주) , 자동 저장(보조))
주된 쓰레드가 종료되면 보조 쓰레드는 더이상 존재할 이유가 없음, 그런데 주된 쓰레드가 종료되어도
보조 작업 쓰레드가 종료되지 않는 경우 있음)
다른 쓰레드가 종료되면 자동으로 종료되어야하는 쓰레드(주된쓰레드가 종료되면 보조 작업 쓰레드도 종료되어야 함)
다른 쓰레드가 종료되면 자동으로 종료되는 쓰레드를 ‘데몬 쓰레드’라고 함
우선순위가 가장 낮음
주된 쓰레드에서 데몬쓰레드를 실행시킴
void setDaemon(boolean status) : 데몬 쓰레드 여부를 설정. true - 데몬쓰레드로 사용, false(데몬 쓰레드가 아님)
start() 메소드 호출전에 사용해야 함
◐TheNeedForThread - extends로 쓰레드 구현
단일쓰레드
public class MovieThread extends Thread {
@Override
public void run() { //멀티 쓰레드로 작업할 내용을 넣기
//#1-1. 영상 설정
String[] strVideoArray = {"영상1", "영상2", "영상3", "영상4", "영상5"};
//#2-1. 영상 실행
for(int i = 0 ; i < strVideoArray.length; i++) {
System.out.println(strVideoArray[i] + " ");
try {
Thread.sleep(500); //1000초 -1초, 0.5초 동안 잠시 멈춤,
} catch (Exception e) {
System.out.println("예외가 발생하였습니다.");
}//try ~ catch 끝
}//for 끝
} // run 끝
}//end of class
public class SubtitleThread extends Thread {
//자막을 처리할 클래스
@Override
public void run() {
//자막으로 처리할 내용, 멀티 쓰레드에서 실행할 내용
String[] strSubtitleArray = {"자막1", "자막2", "자막3", "자막4", "자막5"};
try {
Thread.sleep(100); //자막을 0.01초 정도 늦게 출력되도록 설정
// 멀티 쓰레드는 독립적으로 실행되기 때문에 먼저 start()메소드로 호출해도
// 나중에 실행된 쓰레드 보다 늦게 실행 될 수 있음
} catch (InterruptedException e) {
e.printStackTrace();
}
//#2-2. 자막 실행
for(int i = 0 ; i < strSubtitleArray.length; i++) {
System.out.print(strSubtitleArray[i] + " ");
try {
Thread.sleep(500); //1000 -1초, 0.5초 동안 잠시 멈춤
} catch (Exception e) {
System.out.println("예외 발생");
}
}
}
}
public class CreateAndStartThreadExam {
public static void main(String[] args) {
//#1. 메인쓰레드 부분
System.out.println("메인 쓰레드 실행.....");
System.out.println("즐거운 시간.....");
//#2. 영상 쓰레드 생성
// 쓰레드 실행하기 위해서는 쓰레드 객체 생성
Thread movieThread = new MovieThread();
//#2-1. 영상 쓰레드 실행
movieThread.start(); // new MovieThread().start()
//#3. 자막 쓰레드 생성
Thread subtitleThread = new SubtitleThread();
//#3-1. 자막 쓰레드 실행
subtitleThread.start(); // start라는 것은, 다 준비시키고, run실행 진행시켜라라는 메소드인것.
// start가 쓰레드 준비작업과 실행하는 역할까지 가지고 있다.
// 그 후에, run을 호출시킨다.
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
//#4. 메인 쓰레드 부분
System.out.println("다시 메인 쓰레드 부분");
//메인 과 클래스의 쓰레드는 별개이다.
//멀티쓰레드는, 자신의 작업이 끝날떄까지, 계속해서 작업해 나간다.
}
}
◐2번implements로 쓰레드 구현
FunctionalInterface : 함수적 인터페이스, ‘추상 메소드를 하나’만 가질수있다.
이외에 다른 것을 가지고있다면, 오류를 떨어뜨린다.
public class MovieRunnable implements Runnable {
@Override
public void run() {
//#1-1. 영상 설정
String[] strVideoArray = {"영상1", "영상2", "영상3", "영상4", "영상5"};
//#2-1. 영상 실행
for(int i = 0 ; i < strVideoArray.length; i++) {
System.out.println(strVideoArray[i] + " ");
try {
Thread.sleep(500); //1000초 -1초, 0.5초 동안 잠시 멈춤,
} catch (Exception e) {
System.out.println("예외가 발생하였습니다.");
}//try ~ catch 끝
}//for 끝
}//run끝
}
public class SubtitleRunnable implements Runnable {
@Override
public void run() {
//자막으로 처리할 내용, 멀티 쓰레드에서 실행할 내용
String[] strSubtitleArray = {"자막1", "자막2", "자막3", "자막4", "자막5"};
try {
Thread.sleep(100); //자막을 0.01초 정도 늦게 출력되도록 설정
// 멀티 쓰레드는 독립적으로 실행되기 때문에 먼저 start()메소드로 호출해도
// 나중에 실행된 쓰레드 보다 늦게 실행 될 수 있음
} catch (InterruptedException e) {
e.printStackTrace();
}
//#2-2. 자막 실행
for(int i = 0 ; i < strSubtitleArray.length; i++) {
System.out.print(strSubtitleArray[i] + " ");
try {
Thread.sleep(500); //1000 -1초, 0.5초 동안 잠시 멈춤
} catch (Exception e) {
System.out.println("예외 발생");
}
}
}
}
public class CreateAndStartThreadRunnable {
public static void main(String[] args) {
//#1. main Thread
System.out.println("main thread .....");
//이렇게 하는 이유는, 다중상속이 안되기때문에,
//#2. 영상 쓰레드 객체 생성 및 실행
//방법1)
// Runnable movieRunable = new MovieRunnable();
// Thread movieThread = new Thread(movieRunable);
//방법2)
Thread movieThread = new Thread(new MovieRunnable());
movieThread.start();
//#3. 자막 쓰레드 객체 생성 및 실행
Runnable subtitleRunable = new SubtitleRunnable();
Thread subtitleThread = new Thread(subtitleRunable);
subtitleThread.start();
//#4. 메인 쓰레드 부분
try {
Thread.sleep(3000); //3초간 작업을 멈춤
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println();
System.out.println("-----------------");
System.out.println("메인 부분 끝 ....");
}
}
◐익명 구현객체(안드로이드가 주로사용)
3번쨰
익명 - 이름이 없다. jvm 객체생성,
★익명 구현 객체 - 구현(뭐를 interface로 구현)
★익명 객체 - 쓰레드로 구현
Runnable 안에 들어가있는 run()추상메소드
추상메소드를 하나만을 가지고있다. 그래서객체를 못만든다.
Runnable을 implements 한다면, run()추상메소드를 반드시 구현해야한다.
이것을 완성만 한다면, 올라간다.
public class MovieRunnable implements Runnable {
@Override
public void run() {
//#1-1. 영상 설정
String[] strVideoArray = {"영상1", "영상2", "영상3", "영상4", "영상5"};
//#2-1. 영상 실행
for(int i = 0 ; i < strVideoArray.length; i++) {
System.out.println(strVideoArray[i] + " ");
try {
Thread.sleep(500); //1000초 -1초, 0.5초 동안 잠시 멈춤,
} catch (Exception e) {
System.out.println("예외가 발생하였습니다.");
}//try ~ catch 끝
}//for 끝
}//run끝
}
public class SubtitleRunnable implements Runnable {
@Override
public void run() {
//자막으로 처리할 내용, 멀티 쓰레드에서 실행할 내용
String[] strSubtitleArray = {"자막1", "자막2", "자막3", "자막4", "자막5"};
try {
Thread.sleep(100); //자막을 0.01초 정도 늦게 출력되도록 설정
// 멀티 쓰레드는 독립적으로 실행되기 때문에 먼저 start()메소드로 호출해도
// 나중에 실행된 쓰레드 보다 늦게 실행 될 수 있음
} catch (InterruptedException e) {
e.printStackTrace();
}
//#2-2. 자막 실행
for(int i = 0 ; i < strSubtitleArray.length; i++) {
System.out.print(strSubtitleArray[i] + " ");
try {
Thread.sleep(500); //1000 -1초, 0.5초 동안 잠시 멈춤
} catch (Exception e) {
System.out.println("예외 발생");
}
}
}
}
public class AnonymousObjectThread {
public static void main(String[] args) {
//익명 구현객체이든 익명객체이든, 결과값은 똑같다.
//결과값은 같다. 둘의 차이점도 있나요? - 만드는 방법이 여러가지이다. 뭐그런건가요?
//
//익명 구현객체
//#1. main Thread
System.out.println("main thread .....");
Thread runableThread = new Thread(new Runnable() { // 인터페이스로 구현한 / 익명 구현객체
//run()만 완성시킨다면, Runnable을 객체로 생성한다.
@Override
public void run() {
for(int i = 1 ; i <= 5; i++) {
System.out.println("Hellow!!");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//try catch
}// for끝
}//run 끝
});
runableThread.start();
//--------------------------------------------------------------
//변수로 받는다라는 것은, 2번이상
new Thread() { //익명 객체
public void run() {
for(int i = 1; i <= 5; i++) {
System.out.println("java ");
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}//try - catch 끝
}//for 끝
}//run 끝
}.start();
//변수로 받는다라는 것, 2번이상 사용한다는 것.
Thread test = new Thread() { //익명 객체인가요?
public void run() {
for(int i = 1; i <= 5; i++) {
System.out.println("java ");
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}//try - catch 끝
}//for 끝
}//run 끝
}; // method의 끝
test.start();
}//main 끝
}//class 끝
◐데몬쓰레드
4번째
일반적으로 쓰레드는 독립적으로 수행된다.
메인을 종료해도 작업 쓰레드는 계속 실행되는게 일반적이다.
반면에, 데몬쓰레드는 메인의 쓰레드가 종료되면, 데몬쓰레드도 같이 종료가 된다.
public class TestDaemon implements Runnable {
@Override
public void run() {
for(int i = 1 ; i <= 20; i++) {
//#1. 1초 동안 멈춤
try {
Thread.sleep(1000);
} catch (Exception e) {
System.out.println("쓰레드 예외 발생");
}
System.out.println("***** 지금은 보조 작업 쓰레드 실행 *****");
System.out.println(Thread.currentThread().getName());
//currentThread() : 현재 작업 중인 쓰레드
//getName() : 쓰레드 이름 읽어 오기
//setName(쓰레드명) : 쓰레드 이름을 설정
}
}
}
public class CreateAndStartDaemonThread {
public static void main(String[] args) {
//#1. 메인 쓰레드
System.out.println("**** 메인 쓰레드 실행 ****");
/*
//일반 쓰레드
Runnable daemonThread = new TestDaemon();
Thread daemonTh = new Thread(daemonThread);
daemonTh.start();
try {
Thread.sleep(2000);
}catch (Exception e) {
System.out.println("쓰레드 예외 발생");
}
System.out.println("**** 메인 쓰레드 종료 ****");
*/
//데몬 쓰레드
Runnable daemonThread = new TestDaemon();
Thread daemonTh = new Thread(daemonThread);
daemonTh.setDaemon(true);// 데몬 쓰레드로 설정
//주의 -반드시 start()보다 먼저 선언
//
daemonTh.start(); //쓰레드 실행
try {
Thread.sleep(2000);
}catch (Exception e) {
System.out.println("쓰레드 예외 발생");
}
System.out.println("**** 메인 쓰레드 종료 ****");
}
}
'1. JAVA > 3). 자바_개념' 카테고리의 다른 글
자바_개념_Day_32 (0) | 2024.02.15 |
---|---|
자바_개념_Day_31 (2) | 2024.02.14 |
자바_개념_Day_29 (1) | 2024.02.08 |
자바_개념_Day_27 (1) | 2024.02.06 |
자바_개념_Day_26 (1) | 2024.02.05 |