본문 바로가기
웹개발 수업/JAVA

웹개발_JAVA 21

by gugigugi92 2023. 3. 6.

프로그램
         실행이 안된 상태.
프로세스
         실행된 프로그램.
쓰레드
         프로세스 내의 작업 처리경로



-단일 쓰레드

ex) JavaScript 서버(채팅, sns등)
처리 경로를 한 개만 가지고 있기 때문에 직렬적이다.
한 번에 하나씩 처리하기 때문에 상대적으로 비효율적이다.
하지만 하나의 작업에 문제가 발생하더라도 다른 작업은 시작하지 않았기 때문에
다른 작업에는 문제가 발생하지 않는다. 따라서 안정성이 보장되고 설계 시 
멀티 쓰레드에 비해 쉽다.

작업1 작업2 작업3

작업순서 ---->

작업 1이 끝나야 작업 2가시작

(매표소에서 앞사람이 1000장을 사도 1장을 사야하는 사람이 기다려야하는 상황과 같다)

package thread;

import java.sql.Time;

public class Thread1 extends Thread{
	private String data;

	public Thread1() {;}
	
	public Thread1(String data) {
		super();
		this.data = data;
	}
	public String getData() {
		return data;
	}


	public void setData(String data) {
		this.data = data;
	}

	// data를 10번 받는 자원(스레드) run 재정의 
	//여러 스레드들이 해당 하나의 자원에 접근하여 차례로 진행
	@Override
	public void run() {
		for(int i=0; i<5; i++) {
			//sleep 1000은 1초
			System.out.println(data);
			try {sleep(1);} catch (Exception e) {
			}
		}
	}
	
	
}
package thread;

public class ThreadTest {
public static void main(String[] args) {
	Thread1 thread1 = new Thread1("★");
	Thread1 thread2 = new Thread1("♥"); 
//	재정의 한 run 을 바탕으로 단일 구현
	thread1.run(); // run은 단일이라서 별이 다 출력된다음 하트 출력
	thread2.run();

단일스레드 출력결과


-멀티 쓰레드

ex) Java 서버(결제시스템 등)
하나의 프로세스를 동시에 처리하는 것 처럼 보이지만 사실은 매우 짦은 단위로 분할해서 차례로 처리한다.
여러 개의 처리 경로를 가질 수 있도록 하며, 동시에 작업이 가능해진다.
설계하기 굉장히 어려우며, 하나의 쓰레드 문제 발생 시 모든 쓰레드에 문제가 발생한다.
멀티 쓰레드로 설계했다면, 처리량 증가, 효율성 증가, 처리비용 감소의 장점이 있기 때문에
단점을 감수하고 설계하는 편이다.

 

작업1  ->         ->

작업2     ->         ->

작업3        ->         -> 

작업순서 ------------>

여럿의 작업이 일정량씩 진행된다 

(음식점에서 주문 순서와 상관없이 먼저 완성된 음식부터 서빙을하는 상황) 

 

 

package thread;

public class ThreadTest {
public static void main(String[] args) {
//	단일 구현
	Thread1 thread1 = new Thread1("★");
	Thread1 thread2 = new Thread1("♥"); 
//	// 스케줄링: 단일을 멀티로 나눠주는 작업
	thread1.start();
	thread2.start();//start메소드는 멀티

 

멀티 스레드출력결과

★단일 쓰레드와 멀티 쓰레드는 작업순서의 차이가 있을뿐, 처리 속도차이는 없다★

 

 


멀티  쓰레드 구현 방법
핵심: run() 메소드 재정의

1. Thread 클래스 상속↑
2. Runnable 인터페이스 지정(함수 형 인터페이스로서 람다 사용가능)↓

package thread;

// 스레드 객체가아닌 일반 객체이기 
public class Thread2 implements Runnable{
//   runnable 사용하면 강제로 run을 재정의
   public void run() {
      for (int i = 0; i < 5; i++) {
//    	 필드를 만들지 않고 자원에 접근한 스레드의 이름을 가져올수 있다 
         System.out.println(Thread.currentThread().getName());
         try {Thread.sleep(1000);} catch (InterruptedException e) {;}
      }
   };
}

 

package thread;

public class ThreadTest {
public static void main(String[] args) {
	// 스레드를 상속받은게 아님
	Runnable mineral = new Thread2();    
//	 두개의 스레드가 하나의 '자원을 공유' 
	Thread t1 = new Thread(mineral,"?");
	Thread t2 = new Thread(mineral,"!");
  //함수형 인터페이스 runnable을 이용하여 Thread2 클래스를 생성하지않고 람다로 구현하는법  
//		Runnable mineral2 = () -> {
//		for (int i = 0; i < args.length; i++) {
//			System.out.println(Thread.currentThread().getName());
//			try {Thread.sleep(1000);}catch(InterruptedException e) {;}
//		}
//	};
//==================================
//	여러개의 스레드가 하나의 자원을 공유하여 멀티스레드 구현	
	t1.start();
	t2.start();
    }}

출력결과

 


 

join: 사용한 쓰레드가 끝나고 나서 나머지 쓰레드가 실행된다

 

	t1.start();
	t2.start();
//	//단 이미 join()전에 start()된 쓰레드는 멈출 수 없다.
	System.out.println("메인 쓰레드 시작");// 가장 먼저나옴
	try {t1.join();}catch(InterruptedException e) {;}
//
	System.out.println("메인 쓰레드 종료");

 

출력결과


package synchronizedTest;
/*스레드 오류 해결: 
자원 공유시 멀티스레드의 속도가 빠르기때문에 
특정 연산에서 연산 결과를 빼먹을 수 있다(자원 공유 문제)
건너뛰는 부분의 코드만 '동기화'하여 단일로 수정
*/

//여러 스레드가 접근할 자원 만들기
public class ATM implements Runnable{

	int money;
	
	public ATM() {	
		this.money = 8000;
	}
	
	public void run() {	
		for(int i=0; i<2; i++) {
			withdraw();
			try {Thread.sleep(1000);} catch (InterruptedException e) {;
				
			}
		}
	}

	// 자원의 공유 문제 발생 시 동기화를 사용하여, 멀티 환경에서 특정 부분을 단일 환경으로 바꿔줘야 한다.
	// synchronized 블럭 안의 코드는 단일로 실행
	public synchronized void withdraw() {
//		synchronized (this) {//자원을 구현한 객체(자원의 주인) : mutex
//		블럭을 안쓰고 메서드에 넣으면 메서드 자체가 단일이됨
			this.money -=2000;
			System.out.println(Thread.currentThread().getName()+"이(가)2000원 출금");
			System.out.println("현재 잔액:"+this.money+"원");
		}
}

 

package synchronizedTest;

public class CU {
   public static void main(String[] args) {
      ATM atm = new ATM();
      //동일한 자원에 접근중
      Thread mom = new Thread(atm, "엄마");
      Thread son = new Thread(atm, "아들");
      
      mom.start();
      son.start();
   }
}

출력결과



Thread 종료 방법
   1. 필드에 boolean 타입의 변수를 선언하고 run()안에 있는 반복문에 해당 변수가 true일 경우 break 하도록 설계한다.
   2. sleep() 또는 wait(), join() 등의 메소드를 통해 쓰레드 일시정지 상태일 경우
       Thread객체.interrupt()를 사용하여 InterruptedException을 발생시킨다.
       이 때 일시정지 시킨 메소드 부분의 catch를 통해 예외를 잡아주고 원하는 문장을 작성하면 된다.
   3. 쓰레드를 일시정지하는 코드가 없을 경우 Thread.interrupted()의 상태를 확인한다.
       Thread객체.interrupt() 사용 시 Thread.interrupted()의 상태는 true로 변경된다.
   4. System.exit(0)를 사용하면 전체 쓰레드 종료(프로세스 종료)

 

package thread;
// 스레드는 종료후 멈추는게 가능.
// 실행중 정상 종료하기
public class Thread3 implements Runnable{
//   private boolean exit;
//   
//   public boolean isExit() {
//      return exit;
//   }
//
//
//   public void setExit(boolean exit) {
//      this.exit = exit;
//   }

   @Override
   public void run() {
      while(true) {
         System.out.println("작업중..");
//         try {wait();} catch (InterruptedException e) {;}
//         if(exit) {break;}
//         if(Thread.currentThread().isInterrupted()){ //쓰레드를 멈추는 코드가 없을 경우
//            break;
//         }
         try {
            Thread.sleep(10000);
         } catch (InterruptedException e) { //쓰레드를 멈추는 코드가 있을 경우
            System.out.println("오류 발생됨");
            break;
//         }
      }
   }
}}
package thread;

public class InterruptedTest {
   public static void main(String[] args) {
      Thread3 mineral = new Thread3();
      
      Thread thread = new Thread(mineral);
      
      thread.start();
      
      // 1초있다가 정상 종료
      try {Thread.sleep(1000);} catch (InterruptedException e) {;}
      // 원하는때에 종료시키는 메소드
      thread.interrupt();

   }
}

출력결과

 

'웹개발 수업 > JAVA' 카테고리의 다른 글

웹개발_JAVA 22  (4) 2023.03.11
웹개발_JAVA 20  (0) 2023.02.21
웹개발_JAVA 19  (0) 2023.02.15
웹개발_JAVA 18  (2) 2023.02.15
웹개발_JAVA 17  (0) 2023.02.14

댓글