Cohe
16. ParallelStream, Thread 본문
728x90
- alt + shift + o : 자동 import
ParallelStream
- 사용시 병렬 스트림을 쉽게 사용할 수 있다.
- 전체요소를 서브요소로 나누거, 각 서브요소들에게 개별 스레드를 생성해준다.
- 결과를 결합하여 최종 처리 결과를 리턴
- Stream<Object> stream = list.prarllelstream();
- 일반 스트림은 이렇게 쓴다 : Stream<Object> stream = list.stream();
- isParallel() 메서드로 병렬 여부를 확인 가능.
- 스트림 연결하기 :Steam.concat()
- 두 개의 스트림 객체를 연결해서 하나의 새로운 스트림 객체를 생성
스레드
- 프로세스란 실행중인 프로그램을 의미
- 스레드란 프로세스 안에서 작업 수행하는 것
- 프로세스에는 반드시 하나 이상의 스레드가 존재합니다.
package H_java;
public class H01_processEx {
//스레드 (동시에 여러 프로그램 실행)
public static void main(String[] args) {
//프로세스 실행
try {
//메모장 실행
Process p1 = Runtime.getRuntime().exec("notepad.exe");
//그림판 실행
Process p2 = Runtime.getRuntime().exec("mspaint.exe");
p1.waitFor(); //p1 프로세스가 종료될 때까지 대기
p2.destroy(); //p1 프로세스가 종료되면 실행함. destroy 강제 종료 시킨다.
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
- 멀티 스레드의 장점
- cpu, 메모리를 효율적으로 사용할 수 있다.
- 사용자 응답성이 높아진다.
- 작업을 스레드 단위로 분리해서 실행 시간을 줄여 줄 수 있다.
- 멀티 스레드의 단점
- 동기화, 공유 자원의 문제(교착상태 - dead lock) → 식사하는 철학자 문제인 것 같음
- 스레드 생성하는 방법
- Thread 클래스를 상속하는 방법
- Runnable 인터페이스를 구현한 객체를 Thread 객체에 넣어주는 방식
package H_java;
public class H02_threadEx {
public static void main(String[] args) {
Thread t1= new ThreadExtends();
t1.run();
Runnable r = new RunnableImpl();
Thread t2 = new Thread(r);
//동시에 개별적으로 실행을 한다!!!
//익명 함수를 이용해서 구현
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Runnable 구현하는 방법으로 실행");
for(int i=0;i<50;i++){
System.out.println("Thred3 : "+i);
}
}
});
// 람다식 표현
Thread t4 = new Thread(() -> {
System.out.println("t4 스레드 시작");
for (int i = 0; i < 500; i++) {
System.out.println("Thread4: "+i);
}
});
// 스레드 우선순위
// 스레드가 가질 수 있는 우선 순위는 1 ~ 10 사이의 숫자로 10이 가장 높은 우선순위임.
// 중요! 스레드의 우선순위는 절대적 수치가 아닌 상대적 수치
// 우선 순위에 따라서 점유시간과 자원이 주어지게 된다.
// 우선순위 적용방법 - setProperty(int) 1 ~ 10
// 우선순위 적용시 주의 사항
// 1. 우선순위는 상대적 값이다.
// 2. 스레드를 실행하기 전에 지정해야 한다.
// 3. main() 메서드에서 실행하는 스레드의 경우 기본값 5
// 직접 스레드의 우선 순위값을 설정을 하는 것보다 Thread의 static final 필드
// 값을 이용하는 것이 더 좋다.
// 우선 순위 지정( 1 ~ 10, 상수값 이용)
t1.setPriority(Thread.NORM_PRIORITY);
t2.setPriority(Thread.NORM_PRIORITY);
t3.setPriority(Thread.NORM_PRIORITY);
t4.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
t3.start();
t4.start();
System.out.println("main thread 종료");
}
}
//Thread를 상속하는 방식
class ThreadExtends extends Thread{
@Override
public void run() {
System.out.println("스레드 상속 받는 방법으로 실행");
for(int i=0;i<50;i++){
System.out.println("Thread Extends : " + i);
}
}
}
//Runnable 구현체
class RunnableImpl implements Runnable {
@Override
public void run() {
System.out.println("Runnable 구현하는 방법으로 실행");
for(int i=0;i<50;i++){
System.out.println("RunnableImpl : "+i);
}
}
}
- Thread 클래스 상속 - run() 메서드
- Runnable 구현 - run() 추상 메서드
- 스레드가 가질 수 있는 우선 순위는 1~10 사이의 숫자로 10이 가장 높은 우선순위임
- 중요! 스레스의 우선순위는 절대적 수치가 아닌 상대적 수치
- 우선 순위에 따라서 점유 시간과 자원이 주어지게 된다
- 우선순위 적용방법 - setProperty(int) 1~10
- 우선순위 적용시 주의 사항
- 우선순위는 상대적 값이다.
- 스레드를 실행하기 전에 지정해야 한다.
- main()메서드에서 실행하는 스레드의 경우 기본 값은 5다
- 직접 스레드의 우선 순위값을 설정을 하는 것보다 Thread의 static final 필드 값을 이용하는 것이 더 좋다.
package H_java;
public class H03_ThreadEx {
public static void main(String[] args) {
//sleep()
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
int i = 1;
while(true) {
//interrupt 확인
System.out.println("t1 : "+i);
i++;
if (Thread.interrupted()) { //interrupt 발생 여부 확인
System.out.println("인터럽트가 발생했었네요. 반복문 종료합니다.");
break;
}
// sleep 확인
// try {
// Thread.sleep(1000); //1초
// } catch (InterruptedException e) {
// System.out.println(e.getMessage());
//// System.exit(0);
// }
}
System.out.println("스레드 실행 종료");
}
});
t1.start();
//------------------------------------
// interrupt() 메서드
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
t1.interrupt(); // 스레드가 일시 정지 상태이면 예외 발생. sleep interrupted
// join() 메서드
Sum t2 = new Sum();
Sum t3 = new Sum();
t2.start();
t3.start();
try {
t2.join(); // t2 스레드가 종료될때까지 대기
t3.join(); // t3 스레드가 종료될때까지 대기
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
System.out.println("두 스레드의 Sum의 합계 : "+(t2.sum + t3.sum));
//yeild() 일드
YeildThread t4 = new YeildThread();
YeildThread t5 = new YeildThread();
t4.start();
t5.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
t4.iscontinue = false; //t4 스레드 yeild() 즉, 양보
try {
Thread.sleep(100);
} catch (Exception e) { }
t4.iscontinue = true;
try {
Thread.sleep(20);
} catch (Exception e) {}
t4.isbreak = true;
t5.isbreak = true;
}
}
class Sum extends Thread {
int sum = 0;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
sum += i;
}
}
}
class YeildThread extends Thread{
boolean isbreak = false;
boolean iscontinue = true;
@Override
public void run() {
while(!isbreak){
if(iscontinue){
System.out.println(getName()+" 실행중 >.<");
}
else{
System.out.println("양보합니다.");
Thread.yield(); //실행중이 아니라면 양보해라
}
}
System.out.println(getName()+" 종료");
}
}
- 스레드 상태 제어
- 스레드 작업 시 프로그램 중지 및 버그가 발생할 수 있는 부분
- sleep() : 원하는 시간만큼 멈추고 싶을 때 사용, InterruptedException 처리를 강제하기 때문에 try구분 사용 (checked입니다.)
- interrupt : 스레드가 일시정지 상태에 있을 때 예외를 발생시킨다.nterruptedException 예외 발생 시 run()메서드가 정상 종료 시킬 수 있게 한다
- join () : 다른 스레드 실행이 완료 될 떄 까지 기다리는 메서드
- yield() : 다른 스레드에게 실행 양보하는 메서드
- 스레드 동기화
- 여러 스레드가 동작하는 프로그램에서 하나의 객체를 함께 사용하는 경우 의도치 않은 결과를 반환할 수 있다.
- 하나의 스레드가 작업이 끝날 때까지 객체가 변경되지 않도록 하는 것을 동기화 (synchronized)
- 동기화 지정 방법 → synchronized 키워드 사용
- 동기화 메서드 이용
package H_java;
public class H04_ThreadEx {
public static void main(String[] args) {
SmartPhoneGame game = new SmartPhoneGame();
Player1 p1 = new Player1();
p1.setGame(game);
p1.start();
Player2 p2 = new Player2();
p2.setGame(game);
p2.start();
}
}
class SmartPhoneGame{
private int level;
public int getLevel() {
return level;
}
public synchronized void increaseLevel(){
while (true) {
this.level ++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
//현재 스레드의 이름과 레벨 출력
System.out.println(Thread.currentThread().getName()+" LEVEL : "+this.level);
if(this.level%10==0){
break;
}
}
}
}
class Player1 extends Thread{
private SmartPhoneGame game;
public void setGame(SmartPhoneGame game) {
this.game = game;
this.setName("Player1");
}
public SmartPhoneGame getGame() {
return game;
}
@Override
public void run() {
game.increaseLevel();
}
}
class Player2 extends Thread{
private SmartPhoneGame game;
public void setGame(SmartPhoneGame game) {
this.game = game;
this.setName("Player2");
}
public SmartPhoneGame getGame() {
return game;
}
@Override
public void run() {
game.increaseLevel();
}
}
- 동기화 블럭 :
class SmartPhoneGame{
private int level;
public int getLevel() {
return level;
}
public synchronized void increaseLevel(){
synchronized(this){//동기화 블럭
while (true) {
this.level ++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
//현재 스레드의 이름과 레벨 출력
System.out.println(Thread.currentThread().getName()+" LEVEL : "+this.level);
if(this.level%10==0){
break;
}
}
}
}
}
- 동기화에서 사용하는 스레드 작업 메소드
- wait(), notify() : 같이 쓰인다! 객체 자체를 잠그고 작업에 대한 결정권은 notify가 갖는다. 다른 스레드가 실행된다.
- notifyAll() : 멈췄던 애들이 다 실행
package H_java;
public class H06_ThreadEx {
public static void main(String[] args) {
//스레드 객체 생성
DaemonThread dt1 = new DaemonThread();
DaemonThread dt2 = new DaemonThread();
//데몬 스레드로 설정
dt1.setDaemon(true); //이걸로 데몬 스레드임을 알려준다!!
dt2.setDaemon(true);
dt1.start();
dt2.start();
try {
Thread.sleep(5000);
} catch (Exception e) { }
System.out.println("main 종료");
//종료하면 멈춰버린다.
}
}
class DaemonThread extends Thread{
@Override
public void run() {
while (true) {
System.out.println(getName());
try {
sleep(500);
} catch (InterruptedException e) { }
}
}
}
- ThreadGroup
- 스레드 그룹은 관련되어 있는 스레드 별로 그룹핑해서 다루기 위해 사용
- 그룹 안에 또 다른 그룹을 생성하는 것도 가능
- 보안상의 이유로 자신과 하위 그룹을 변경이 가능하다. 하지만 다른 그룹에 대한 모든 변경은 불가능하다.
- 관련 메소드
- activeCount() : 현재 그룹 및 하위 그룹의 모든 스레드 수 리턴
- activeGroupCount() : 현재 그룹의 모든 하위 그룹 수 리턴
- getMaxPriority() : 현재 그룹에 스레드가 가질 수 있는 최대 우선 순위 값 리턴
- setMaxPriority(int priority) : 최대 우선순위 값 설정
- getName() : 현재 그룹의 이름 리턴
- getParent() : 현재그룹의 부모 그룹 리턴
- parentof(ThreadGroup g) : 현재 그룹이 g의 부모그룹인지 여부 리턴
- isDaemon() : 현재 그룹이 Daemon 그룹인지 여부 리턴
- setDaemon(boolean daemon) : 데몬 그룹으로 설정
- list() : 현재 그룹에 포함된 스레드와 하위 그룹 정보 출력
- intrrupt : 현재 그룹에 포함된 모든 스레드 중지
- 동작 이제 안함!!
- checkAccess() : 스레드 그룹을 변경할 권한이 있는지 여부를 리턴한다.
- destroy() : 현재 그룹의 모든 하위 그룹을 삭제한다.
- isDestroyed() : 현재 그룹이 삭제 되었는지 여부 확인
package H_java;
public class H07_ThreadEx {
public static void main(String[] args) {
//스레드 설정 그룹
//1. 그룹 객체 생성
ThreadGroup group = new ThreadGroup("group1");
//2. 스레드 그룹에 스레드 추가
MyThread t1 = new MyThread(group, "t1");
MyThread t2 = new MyThread(group, "t2");
MyThread t3 = new MyThread(group, "t3");
//3. 스레드 그룹 시작
t1.start();
t2.start();
t3.start();
try {
Thread.sleep(3000);
} catch (Exception e) {
// TODO: handle exception
}
group.interrupt();
System.out.println("그룹 스레드 숫자 : "+group.activeCount());
System.out.println("그룹 숫자 : "+group.activeGroupCount());
group.checkAccess();
group.destroy();
group.isDaemon();
System.out.println("그룹의 부모를 리턴 "+ group.getParent());
group.list();
}
}
class MyThread extends Thread{
public MyThread(ThreadGroup g, String name){
super(g,name);
}
@Override
public void run() {
while(true){
System.out.println(getName());
try {
sleep(500);
} catch (Exception e) {
System.out.println(e.getMessage() + "interrupt 발생");
break;
}
}
System.out.println(getName()+ "종료");
}
}
'개발 언어 > JAVA' 카테고리의 다른 글
고객 관리 프로그램 작성 (0) | 2024.03.31 |
---|---|
17. Network, 서버 만들기! (0) | 2024.03.28 |
15. Operator, Stream (0) | 2024.03.27 |
14 람다식 (0) | 2024.03.25 |
13 객체 정렬을 위한 객체 간 크기 비교, 제너릭 , File 입출력 (0) | 2024.03.21 |