프로세스(process)란?

    보통 프로세스라고 함은 실행 중인 하나의 프로그램을 말한다.

    -하나의 프로그램이 여러 개의 프로세스를 만들기도 한다.(ex. 인터넷 창 등)

    멀티 태스킹 (multi tasking)

    멀티 테스킹은 통상 두 가지 이상의 작업을 동시에 처리하는 것을 칭한다.

    구현 방법

    멀티 프로세스

    -> 독립적 프로그램을 여러 개 실행 처리

    멀티 스레드

    -> 하나의 프로그램을 실행하여, 내부적으로 여러 가지 작업을 처리하는 것

    메인 스레드(main thresd)

    모든 자바 프로그램은 JVM의 메인 스레드가 main()를 실행하면서 시작한다.

    메인 스레드와 작업 스레드

    메인 스레드는 스레드들을 만들어서 병렬로 코드를 실행할 수 있으며,

    그것이 곳, 멀티 태스킹을 수행하는 것이다.

    프로세스의 종료

    메인 스레드가 작업 스레드보다 먼저 종료되더라도, 작업 스레드가 계속 실행 중이라면,

    프로세스는 종료되지 않는다.

    작업 스레드 생성과 실행

    몇 개의 작업을 병렬로 실행해야 할지 설계 단에서 결정해야 한다.

    작업 스레드를 생성하는 방법은 아래와 같다.

    Thread 클래스로부터 직접 생성한다.

    Thread 하위 클래스로부터 생성한다.

     

    package kr.co.kihd.singlethread;
    
    import java.awt.Toolkit;
    
    public class BeepSoundTest {
    	
    	//main()은 JVM이 실행한다.
    	public static void main(String[] args) {
    		//현재 실행중인 스레드명을 출력함.
    		System.out.println(Thread.currentThread().getName());
    		
    		//Toolkit은 추상클래스인데, 그중에 GUI관련된 메서드들로 구성되어진 인스턴스를
    		//getDefaultToolkit()를 통해서 참조를 얻어냄.
    		Toolkit toolkit = Toolkit.getDefaultToolkit();
    		for(int i = 0; i < 5; i++) {
    			System.out.println("for문을 실행하는 스레드 이름 : " + 
    					Thread.currentThread().getName());
    			toolkit.beep();	//비프음 출력
    			try {
    				Thread.sleep(500);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			
    		}
    		
    		for(int i = 0; i<5; i++) {
    			System.out.println("삐슝~");
    			
    			try {
    				Thread.sleep(500);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		
    		//싱글스레드를 멀티스레드로 바꿔서 프로그램을 만드는것이 우리의 목표임.
    	}
    	
    }
    

    package kr.co.kihd.singlethread;
    
    import java.awt.Toolkit;
    
    public class BeepSoundTest {
    	
    	//main()은 JVM이 실행한다.
    	public static void main(String[] args) {
    		//현재 실행중인 스레드명을 출력함.
    		System.out.println(Thread.currentThread().getName());
    		
    		//Toolkit은 추상클래스인데, 그중에 GUI관련된 메서드들로 구성되어진 인스턴스를
    		//getDefaultToolkit()를 통해서 참조를 얻어냄.
    		Toolkit toolkit = Toolkit.getDefaultToolkit();
    		for(int i = 0; i < 5; i++) {
    			System.out.println("for문을 실행하는 스레드 이름 : " + 
    					Thread.currentThread().getName());
    			toolkit.beep();	//비프음 출력
    			try {
    				Thread.sleep(500);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			
    		}
    		
    		for(int i = 0; i<5; i++) {
    			System.out.println("삐슝~");
    			
    			try {
    				Thread.sleep(500);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		
    		//싱글스레드를 멀티스레드로 바꿔서 프로그램을 만드는것이 우리의 목표임.
    	}
    	
    }
    

    직접 생성하는 멀티스레드 방법 3가지
    방법 1 --> 구현 객체 (Runnable) 대입 

    방법 2 --> 익명 구현 객체

    방법 3 --람다식(함수적 인터페이스) JDK1.8, 코드 절약, 가독성

    package kr.co.kihd.multithread1;
    
    import java.awt.Toolkit;
    
    //Runnable인터페이스를 직접 구현하고 있다.
    public class Beep implements Runnable{
    	
    	@Override
    	public void run() {
    		Toolkit toolkit = Toolkit.getDefaultToolkit();
    		for(int i = 0; i < 5; i++) {
    			System.out.println("for문을 실행하는 스레드 이름 : " + 
    					Thread.currentThread().getName());
    			toolkit.beep();	//비프음 출력
    			try {
    				Thread.sleep(500);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			
    		}
    		
    	}
    	
    }
    
    package kr.co.kihd.multithread1;
    
    import java.awt.Toolkit;
    
    public class BeepSoundTest {
    	
    	//main()은 JVM이 실행함.
    	public static void main(String[] args) {
    		
    		//직접 생성하는 멀티스레드 방법 3가지
    		//방법 1 --> 구현객체 (Runnable) 대입 
    //		Runnable runnable = new Beep(); //구현객체 대입
    //		Thread thread = new Thread(runnable);
    //		thread.start();
    		
    		//방법 2 --> 익명구현객체
    //		Thread thread = new Thread(new Runnable() {
    //			
    //			@Override
    //			public void run() {
    //				
    //				Toolkit toolkit = Toolkit.getDefaultToolkit();
    //				for(int i = 0; i < 5; i++) {
    //					System.out.println("for문을 실행하는 스레드 이름 : " + 
    //							Thread.currentThread().getName());
    //					toolkit.beep();	//비프음 출력
    //					try {
    //						Thread.sleep(500);
    //					} catch (InterruptedException e) {
    //						e.printStackTrace();
    //					}
    //					
    //				}
    //				
    //			}
    //		});
    //		
    //		thread.start();
    		
    		//방법 3 --람다식(함수적 인터페이스) JDK1.8, 코드절약, 가독성
    		Thread thread = new Thread( ()-> {
    			
    			Toolkit toolkit = Toolkit.getDefaultToolkit();
    			for(int i = 0; i < 5; i++) {
    				System.out.println("for문을 실행하는 스레드 이름 : " + 
    						Thread.currentThread().getName());
    				toolkit.beep();	//비프음 출력
    				try {
    					Thread.sleep(500);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				
    			}
    			
    		});
    		
    		for(int i = 0; i<5; i++) {
    			System.out.println("for문을 실행하는 스레드 이름 : " + 
    					Thread.currentThread().getName());
    			System.out.println("삐슝~");
    			
    			try {
    				Thread.sleep(500);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		
    	}
    
    }
    

    for문을 실행하는 스레드 이름 : main
    삐슝~
    for문을 실행하는 스레드 이름 : Thread-0
    for문을 실행하는 스레드 이름 : main
    삐슝~
    for문을 실행하는 스레드 이름 : Thread-0
    for문을 실행하는 스레드 이름 : main
    삐슝~
    for문을 실행하는 스레드 이름 : Thread-0
    for문을 실행하는 스레드 이름 : main
    삐슝~
    for문을 실행하는 스레드 이름 : Thread-0
    for문을 실행하는 스레드 이름 : main
    삐슝~
    for문을 실행하는 스레드 이름 : Thread-0


    작업 스레드의 이름

    스레드의 이름

    메인 스레드 이름 : main -> JVM 생성과 동시에 부여함

    작업 스레드 이름 (자동 설정) : Thread-n

     

    동시성과 병렬성

    동시성 - 멀티 작업 위해 하나의 코어에서 멀티 스레드가 번갈아 가며 실행하는 성질

    병행성 - 멀티 작업을 위해 멀티 코어에서 개별 스레드를 동시에 실행하는 성질

     

    package kr.co.kihd.multithread2;
    
    import java.awt.Toolkit;
    
    //thread 클래스 자체를 상속을 받아서 스레드 클래스로 만듬
    public class Beep extends Thread {
    	
    	@Override
    	public void run() {
    		Toolkit toolkit = Toolkit.getDefaultToolkit();
    		for(int i = 0; i < 5; i++) {
    			System.out.println("for문을 실행하는 스레드 이름 : " + 
    					Thread.currentThread().getName());
    			toolkit.beep();	//비프음 출력
    			try {
    				Thread.sleep(500);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			
    		}
    	
    	}
    	
    }
    
    package kr.co.kihd.multithread2;
    //Thread를 상속한 Beep클래스를 이용한 구현
    public class BeepTest {
    
    	public static void main(String[] args) {
    		Thread thread = new Beep();  //필드의 다형성
    		thread.start();
    		
    		for(int i = 0; i<5; i++) {
    			System.out.println("삐슝~");
    			
    			try {
    				Thread.sleep(500);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    
    	}
    
    }
    

    타이머 만들기 예제

    package kr.co.kihd.multithread3;
    
    public class TimerThread extends Thread {
    	
    	@Override
    	public void run() {
    		
    		for(int i = 10; i>0; i--) {
    			System.out.println("남은 시간 : " + i);
    			
    			try {
    				Thread.sleep(1000);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			
    		}
    	}
    	
    }
    
    package kr.co.kihd.multithread3;
    
    import javax.swing.JOptionPane;
    
    public class TimerTest {
    
    	public static void main(String[] args) throws Exception {
    		Thread thread = new TimerThread();
    		thread.start();
    		
    		String input = JOptionPane.showInputDialog("10초 안에 값을 입력하세요.");
    		if(input != null){
    			System.out.println("입력 값 : " + input);
    			System.exit(0);
    		}else {
    			Thread.sleep(10000);		//10초를 대기한다.
    			System.out.println("입력하지 못했습니다. 삐쓩!!");
    			System.exit(0);
    		}
    		
    	}
    
    }
    

    남은 시간 : 10
    남은 시간 : 9
    남은 시간 : 8
    남은 시간 : 7
    남은 시간 : 6
    남은 시간 : 5
    남은 시간 : 4
    남은 시간 : 3
    남은 시간 : 2
    남은 시간 : 1
    입력하지 못했습니다. 삐쓩!!

     


    스레드의 이름을 얻는 2가지 방법

    1번째(정적 메서드 이용)
     Thread.currentThread(). getName()
     2번째(인스턴스 메서드 이용)
     this.getName()

    package kr.co.kihd.threadname;
    
    public class ThreadGumi extends Thread{
    	
    	public ThreadGumi() {
    		this.setName("ThreadGumi"); //스레드 이름을 지정하고 있다.
    	}
    	
    	@Override
    	public void run() {
    		System.out.println("[현재 실행 중인 스레드] : " + this.getName());
    		for(int i = 0; i<5; i++) {
    			System.out.println(this.getName() + "가 출력한 내용 : " + i);
    		}
    	}
    	
    }
    
    package kr.co.kihd.threadname;
    
    public class ThreadDaegu extends Thread{
    	
    	public ThreadDaegu() {
    		this.setName("ThreadDaegu"); //스레드 이름을 지정하고 있다.
    	}
    	
    	@Override
    	public void run() {
    		System.out.println("[현재 실행 중인 스레드] : " + this.getName());
    		for(int i = 0; i<5; i++) {
    			System.out.println(this.getName() + "가 출력한 내용 : " + i);
    		}
    		
    		//스레드의 이름을 얻는 2가지 방법
    		/*
    		 * 1번째(정적메서드 이용)
    		 * Thread.currentThread().getName()
    		 * 2번째(인스턴스 메서드 이용)
    		 * this.getName()
    		 */
    	}
    	
    }
    

    스레드 우선순위

    스레드 스케줄링

    스레드의 개수가 코어의 수보다 많을 경우

    스레드를 어떤 순서로 동시성으로 실행할 것인가 경정 -> 스레드 스케줄링

    스케줄링에 의해 스레드들은 번갈아 가며 run() 메서드를 조금씩 실행

     

    스레드 우선순위

    스레드들이 동시성을 가질 경우 우선적으로 실행할 수 있는 순위

    우선순위는 1(낮음)에서부터 10(높음)까지로 부여

     =모든 스레드의 우선순위는 5의 우선순위

    package kr.co.kihd.priority;
    
    public class CalcThread extends Thread {
    
    	long sum;
    	
    	public CalcThread(String name) {
    		this.setName(name);
    	}
    	
    	@Override
    	public void run() {
    		for(int i = 0; i<20000000; i++) {
    			sum += i;
    		}
    		System.out.println("[작업 완료 스레드] : " + this.getName());
    		System.out.println("[합계] : " + this.sum);
    	}
    	
    }
    
    package kr.co.kihd.priority;
    
    public class PriorityTest {
    
    	public static void main(String[] args) {
    		
    		Thread thread0 = Thread.currentThread();
    		System.out.println(thread0.getName() + " : " + thread0.getPriority());
    		
    		for(int i = 1; i <= 5; i++) {
    			Thread thread = new CalcThread("Thread : " + i);
    			
    			//Thread1,2,3,4는 우선운위가 가장 낮다.
    			if(i != 5) {
    				thread.setPriority(Thread.MIN_PRIORITY);
    				//thread.setPriority(1); //위와 동일
    			}
    			//우선순위가 10으로 가장 높다.
    			else {
    				thread.setPriority(Thread.MAX_PRIORITY);
    				//thread.setPriority(10); //위와 동일
    			}
    			thread.start();
    			
    		}
    
    	}
    
    }
    

    동기화 메서드와 동기화 블록

    공유 객체를 사용할 때의 주의할 점

    멀티 스레드가 하나의 객체를 공유해서 생기는 오류

     

    동기화 메서드 및 동기화 블록

    단 하나의 스레드만 실행할 수 있는 메서드 또는 블록을 말한다.

    다른 스레드는 메서드블록이 실행이 끝날 때까지 대기해야 한다.

     

    동기화가 되는 영역 => 임계 영역

    해당 객체를 독점적으로 사용할 수 있는 권한 => 모니터

     

    synchronized 

    한 스레드만이 독점적으로 실행되어야 하는 부분(동기화 코드)을 표시하는 키워드

    임계 영역을 표기하는 키워드

     

    wait()

    다른 스레드가 notify()를 불러줄 때까지 기다린다.

    notify()

    특정한 스레드 하나만 깨워주는 메서드

    notifyAll()

    대기 중인 거 다 깨워주는 메서드

     

     

    동기화 예제

    package kr.co.kihd.synchronizedd;
    //공유객체
    public class Calculator {
    	
    	private int memory;
    	int value = 100;
    	
    	
    	public int getMemory() {
    		return this.memory;
    	}
    	
    	//동기화 메서드 => 데이터 신뢰성 보장하기 위해 반드시 동기화처리가 필수다.
    	public synchronized void setMemory(int memory) {
    		this.memory = memory;
    		
    		//1초간 일시정지
    		//System.out.println(Thread.currentThread().getName());
    		
    		try {
    			Thread.sleep(1000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		System.out.println(Thread.currentThread().getName() + 
    							" : " + this.getMemory());
    	}
    	
    	//비동기화 메서드
    	public synchronized void print() {
    		System.out.println(Thread.currentThread().getName() + 
    				" " + "value값 : " + this.value);
    		for(int i = 0; i<10; i++) {
    			System.out.println(Thread.currentThread().getName()
    					+" " + i);
    		}
    	}
    }
    
    package kr.co.kihd.synchronizedd;
    
    public class UserA extends Thread {
    	
    	//공유객체 
    	private Calculator calculator;
    	
    	public void setCalculator(Calculator calculator) {
    		this.calculator = calculator;
    		this.setName("UserA"); //스레드 이름 지정
    	}
    	@Override
    	public void run() {
    		this.calculator.print();
    		//공유객체의 필드인 memory값에 100을 변경
    		this.calculator.setMemory(100);
    
    	}
    	
    }
    
    package kr.co.kihd.synchronizedd;
    
    public class UserB extends Thread {
    	
    	//공유객체 
    	private Calculator calculator;
    	
    	public void setCalculator(Calculator calculator) {
    		this.calculator = calculator;
    		this.setName("UserB"); //스레드 이름 지정
    	}
    	@Override
    	public void run() {
    		this.calculator.print();
    		//공유객체의 필드인 memory값에 50을 변경 //서로다른 메모리값 주기.
    		this.calculator.setMemory(50);
    
    	}
    	
    }
    
    package kr.co.kihd.synchronizedd;
    
    public class NnsynchronizedTest {
    
    	public static void main(String[] args) {
    		
    		//공유객체 생성
    		Calculator calculator = new Calculator();
    		
    		UserA userA = new UserA();
    		userA.setCalculator(calculator);
    		
    		UserB userB = new UserB();
    		userB.setCalculator(calculator);
    		
    		userA.start();
    		userB.start();
    		
    	}
    
    }
    

    화장실 예제 동기화

    package kr.co.kihd.synchronizedd2;
    
    public class Toilet {
    	
    	//플레그 변수
    	private boolean seat;
    	
    	public synchronized void use() throws Exception {
    		String name = Thread.currentThread().getName();
    		if(this.seat == false) {
    			System.out.println(name + "가/이 화장실에 침입했습니다.");
    			this.seat = true;
    			
    			Thread.sleep(1000);
    			System.out.println(name + " 가/이 말 : 아 시원하다!");
    			
    			this.seat = false;
    			System.out.println(name + " 가/이 화장실 사용을 마쳤습니다.");
    			System.out.println();
    		}
    		else {
    			System.out.println(name + " 가/이 화장실 사용중입니다. 기다려주세요!");
    		}
    	}
    	
    	public synchronized void noke() {
    		System.out.println(Thread.currentThread().getName() +
    								" 똑똑!");
    	}
    	
    }
    
    package kr.co.kihd.synchronizedd2;
    
    public class UsingToilet extends Thread {
    	
    	//공유객체
    	private Toilet toilet;
    	
    	public UsingToilet(Toilet toilet, String name) {
    		this.toilet = toilet;
    		this.setName(name);
    	}
    	
    	@Override
    	public void run() {
    		try {
    			this.toilet.noke();
    			this.toilet.use();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    	
    	
    }
    
    package kr.co.kihd.synchronizedd2;
    
    public class ToiletTest {
    
    	public static void main(String[] args) {
    		Toilet toilet = new Toilet();
    		
    		Thread thread1 = new UsingToilet(toilet, "아버지");
    		Thread thread2 = new UsingToilet(toilet, "어머니");
    		Thread thread3 = new UsingToilet(toilet, "아들");
    		Thread thread4 = new UsingToilet(toilet, "딸");
    		
    		thread1.start(); thread2.start(); 
    		thread3.start(); thread4.start();
    		
    
    	}
    
    }
    

    스레드 6가지 상태값 확인

    package kr.co.kihd.state;
    //스레드의 상태를 알아보기 위한 클래스
    public class TargetThread extends Thread{
    	
    	@Override
    	public void run() {
    		
    		//20억번 루핑, 실행 -> 실행대기(Runnable) -> 실행
    		for(long i=0; i<2000000000; i++) {
    			
    		}
    		
    		//일시정지(TIMED_WAITING)
    		try {
    			Thread.sleep(3000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		//20억번 루핑, 실행 -> 실행대기(Runnable) -> 실행
    		for(long i=0; i<2000000000; i++) {
    					
    		}
    	} //종료(TERMINATED)
    }
    
    package kr.co.kihd.state;
    
    public class StatePrintThread extends Thread{
    	
    	//스레드의 상태를 알아보기 위한 멤버로 선언
    	//참조번지를 갖는 객체 추가
    	private TargetThread targetThread;
    	
    	public StatePrintThread(TargetThread targetThread) {
    		this.targetThread = targetThread;
    	}
    	
    	@Override
    	public void run() {
    		while(true) {
    			//스레드의 상태정보를 알아낸다.
    			//Thread.state는 Thread클래스 Enum(열거체)타입이다.
    			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(100);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			
    		}
    	}
    	
    }
    
    package kr.co.kihd.state;
    
    public class ThreadStateTest {
    
    	public static void main(String[] args) {
    		//스레드의 라이프사이클을 알아보는 내용
    		Thread thread = new StatePrintThread(new TargetThread());	
    		thread.start();
    	}
    
    }
    

    타겟스레드의 상태 : NEW
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : TIMED_WAITING
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : RUNNABLE
    타겟스레드의 상태 : TERMINATED

     

     

     

     

     

     

    • 네이버 블러그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기
    loading