다연이네

[days26] 스레드(Thread) 본문

Java

[days26] 스레드(Thread)

 다연  2020. 10. 26. 23:11
반응형

1. 프로세스

- 실행 중( OS로부터 실행에 필요한 자원(메모리)을 할당받아 )인 프로그램
- 프로세스 = 자원(메모리)+스레드
- 모든 프로세스는 최소한 1개 이상의 스레드가 존재
- 2개 이상 스레드가 존재하면 -> 멀티스레드 프로세스
2. 스레드

프로세스의 자원을 이용해서 실제 작업을 수행하는 것
3. 멀티태스킹

OS 차원의 여러 프로그램을 동시에 실행 ,자동으로 프로세스를 관리 
4. 교착상태(deadlock) 
    1) A가 화장실 들어가서 죽었는지 어쨌는지 안나옴
    2) 두 스레드가 자원을 점유한 상태에서 서로 상대편이 점유한 자원을 사용하려고 기다리느라 진행이 멈춰있는 상태

 

 

스레드 사용해보기 - 장보기/대청소

 

 

출력은 CPU마다 다르며, 순서가 뒤죽박죽이다.

 

 

파일 복사하기 - 스레드 사용

package days26;

import java.awt.Button;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @author dayeon
 * @date 2020. 10. 26 -오후 2:10:19
 * @subject 
 * @content
 */
public class Ex05 {

	public static void main(String[] args) {
		// days25 04_02
		String originalpath  = "C:\\Users\\82103\\days25copy.txt";
		String copyPath = "C:\\Users\\82103\\Documents\\dayon.txt";
		
		FileCopy target = new FileCopy(originalpath, copyPath);
		
		System.out.println(" = Copy End = ");

	}

}

class FileCopy extends Frame implements Runnable{ //Runnable을 impements한 스레드 객체
	String originalpath ;
	String copyPath ;
	
	Button btnFileCopy; //t1.start() 버튼을 클릭하면 복사 시작하도록
	
	
	//생성자
	public FileCopy() {
		super();
	}

	public FileCopy(String originalpath, String copyPath) {
		super();
		this.originalpath = originalpath;
		this.copyPath = copyPath;
		
		this.setTitle(this.originalpath+"파일 복사 중...");
		this.setSize(500, 100);
		this.setVisible(true);
		
		Thread t1 = new Thread(this, "t1"); //타겟이 자기자신이니까 target 대신 this
		//== 밑 두줄 코딩과 같다
		//Runnable target = new CleaningWorker();
		//Thread t2 = new Thread(target, "t2"); //이름 이렇게 줘도 좋고
		
		this.btnFileCopy = new Button("File Copy");
		this.btnFileCopy.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				t1.start(); //버튼을 클릭하면 t1 시작, -> run 독립적으로 실행 (복사 실행)
				
			}
		});
		this.add(this.btnFileCopy); //버튼을 프레임 안에 추가
	}

	@Override
	public void run() {
		//독립적으로 originalPath -> coptPath 파일 복사
		long startTime = System.nanoTime(); 
		File orginalfile = new File(originalpath);
		System.out.println(orginalfile.length()+"bytes 복사 예정"); 
		FileInputStream fis = null;
		FileOutputStream fos = null;
		
		final int BUFFER_SIZE =  1024;
		byte [] buffer = new byte[BUFFER_SIZE]; 
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null; 
		
		try {
			fis = new FileInputStream(orginalfile);
			fos = new FileOutputStream(copyPath);
			
			bis = new BufferedInputStream(fis, BUFFER_SIZE); 
			bos = new BufferedOutputStream(fos, BUFFER_SIZE);
			
			int n = 0; 
			
			while ((n = bis.read(buffer))!=-1) {
				bos.write(buffer, 0, n);
			}
			bos.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				bis.close();
				bos.close();
				
				fis.close();
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		 long estimatedTime = System.nanoTime() - startTime;
		 System.out.println("> 처리 시간 : "+estimatedTime+"ns");
		
	}
	
}

 

InputDialog

package days26;

import javax.swing.JOptionPane;

public class Ex06 {

	public static void main(String[] args) {
		//p736
		//main스레드가 혼자 작업하는 것
		String input = JOptionPane.showInputDialog("아무 값이나 입력하세요"); //입력용 대화상자(다이얼로그상자)
		
		//확인버튼을 누르기 전까지 스레드가 멈춰있는 것
		System.out.println(input);
		
		System.out.println("=END=");

	}

}

콘솔창 출력

스레드의 우선순위(우선권)

- 각 스레드마다 우선순위를 설정할 수 있다.
- setPriority(1~10)
- 10 우선순위 최상 ~ 1 우선순위 최하  (설정하지 않으면 5)

package days26;

public class Ex08 {

	public static void main(String[] args) {
				
		PriorityWorker[] p = new PriorityWorker[10];
		for (int i = 0; i < p.length; i++) {
			p[i] = new PriorityWorker();
			p[i].setPriority(i+1); //1~10
			p[i].setName("t"+(i));
		}
		
		for (int i = 9; i >= 0; i--) {
			p[i].start();
		} 
        //운영체제가 알아서 start시키기 때문에 우선권 상관없이 시작-종료 됨 스레드가 이런부분이 어렵다는 것 ..100프로장담을 못한다
		
		System.out.println("> main 스레드 종료 <<");
	}//main

}

class PriorityWorker extends Thread{
	@Override
	public void run(){
		String tName = this.getName();
		int tPriority = this.getPriority();
		
		System.out.printf("%s[우선권: %d] 시작\n", tName, tPriority);
		for (int i = 0; i <10000; i++) {
			try {
				this.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.printf("%s[우선권: %d] 종료\n", tName, tPriority);
	}
}

 

yield() - 다른 스레드에게 양보한다.

- 스레드 자신에게 주어진 실행시간을 다음 차례의 스레드에게 양보(yield)하는 메소드

- 다시 실행대기상태로 간다.(RUN -> RUNNABLE)

- yield(), interrupt()를적절히 사용하면 프로그램의 응답성도 높이고 보다 효율적인 실행이 가능하다.

class YieldThread_A extends Thread{
	public boolean stop = false; //스레드 멈춤 표시(플래그)
	public boolean work = true; //작업 진행 표시(플래그)	true 작업진행해라
	@Override
	public void run() {
		while(!stop) {
			if(work) {
				System.out.println("A 작업 내용...");
			}else {
				System.out.println("t1 스레드가 작업 X -> 다른 스레드에게 양보했다");
				Thread.yield(); //작업 시간을 넘겨줌, 시간 훨씬 줄어든다
			}
		}
		System.out.println("A 작업 종료");
	}
	
	
	
}

Join() - 다른 스레드의 작업을 기다린다.

- 다른 스레드의 작업을 기다린다.
- 지정된 시간이 지나거나 작업이 종료되면 join() 메소드를 호출한 스레드로 다시 돌아와 실행을 계속한다.

package review;

public class Re04 {

	public static void main(String[] args) {
		JoinThread j = new JoinThread();
		j.start();

		
		try {
			j.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} 
        //만약 이 j.join()이 없다면 main스레드가 먼저 실행되어
        //getSum = 0이 찍힌 후 j스레드가 실행 됨
        
		System.out.println("1~10까지의 합은"+j.getSum());
	}

}
class JoinThread extends Thread{
	private int n =10;
	private long sum = 0;
	public int getN() {
		return n;
	}
	public void setN(int n) {
		this.n = n;
	}
	public long getSum() {
		return sum;
	}
	public void setSum(long sum) {
		this.sum = sum;
	}
	@Override
	public void run() {
		for (int i = 1; i <=n; i++) {
			System.out.println(i);
			sum+=i;
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
		}
	}
	
	
	
}

wait()과 notify() 

특정 스레드가 객체의 락을 가진 상태로 오랜 시간을 보내지 않도록 해준다. 

동기화된 임계영역의 코드를 수행하다가 작업을 더이상 진행할 상황이 아니면 일단 wait()를 호출하여 스레드가 락을 반납하고 기다리게 한다. 그러면 다른 스레드가 락을 얻어 해당 객체에 대한 작업을 수행할 수 있게 된다. 나중에 작업을 진행할 수 있는 상황이 되면 notify()를 호출하여 작업을 중단했던 스레드가 다시 락을 얻어 작업을 진행할 수 있게 한다.

 ( wait : runnable에 기다리는게 아니라 notrunnable 상태에서 기다리는 것 (나와서 알려줄때까지) )

package review;

import java.util.Vector;



public class Re09 {
	static VideoShop vShop = new VideoShop();
	public static void main(String[] args) {
		
		System.out.println("> main 스레드 시작");
		
		Person p1 = new Person("p1");
		Person p2 = new Person("p2");
		Person p3 = new Person("p3");
		Person p4 = new Person("p4");
		

		p1.start();
		p2.start();
		p3.start();
		p4.start();
		
		Person p5 = new Person("p5");
		p5.start();
		
		
		
		
	}

}

class VideoShop{
	private Vector<String> buffer = new  Vector<String>();

	public VideoShop() {
		this.buffer.addElement("은하철도 999-0");
		this.buffer.addElement("은하철도 999-1");
		this.buffer.addElement("은하철도 999-2");
		this.buffer.addElement("은하철도 999-3");
	}
	
	public  String lendVideo() throws InterruptedException {
		synchronized (Re09.vShop) {
			
		Thread t = Thread.currentThread();
		if(this.buffer.size()==0) {
			System.out.println(t.getName()+"대기상태 진입(wait)");
			this.wait(); //빌릴게 없으면 기다리겠다
			System.out.println(t.getName()+"대기상태 해제(notify)");
			
		}
		String v = this.buffer.remove(this.buffer.size()-1);
		return v;

		}
	}
	
	public void returnVideo(String video) {
		synchronized (Re09.vShop) {
			
		
		this.buffer.addElement(video);
		}
	}
	
	
}

class Person extends Thread{
	public Person(String name) {
		this.setName(name);
	}

	@Override
	public void run() {
		
		try {
			String v = Re09.vShop.lendVideo();
			System.out.println(this.getName()+" : "+v+" 대여"); 
			System.out.println(this.getName()+" : "+v+" 보는 중"); 
			this.sleep(5000);
			System.out.println(this.getName()+" : "+v+" 반납");
			Re09.vShop.returnVideo(v);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	
}

반응형
Comments