멀티 스레드

동시에 여러 작업을 병행하기 위해 다중의 스레드를 생성하여 운영하는 방식.

한개 이상의 스레드를 실행하면 실행결과가 섞여서 나오는데이때 순서를 정하는 방법으로

Round-Robin(순환할당) 방식과 Priority(우선순위) 방식이 있다.

아래의 예제에서는 setPriority()메소드를 사용하여 우선순위를 정하는 방식으로 스레드의 순서를 정해주었다.

우선순위가 높을수록 실행상태를 더 많이 가지게 된다.

*java.lang 패키지에 Thread클래스 있어 따로 import 해주지 않아도 된다(기본으로 포함됨)

import java.io.*;
public class MultiThread {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		System.out.println("실행시킬 단?");
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		int dan=Integer.parseInt(br.readLine());
		GuGu gu=new GuGu(dan);
		//생성자인수로 Runnable 객체 전달->Thread객체 생성
		Thread t=new Thread(gu);
		
        PrintThread pt=new PrintThread();

        t.setPriority(10);//Thread.MAX_PRIORITY
        pt.setPriority(Thread.MIN_PRIORITY);//1
        t.start(); pt.start();
	}
}
//Runnable 구현(Thread 상속 권장)
class GuGu implements Runnable{
	private int dan;
	public GuGu(int dan) {
		this.dan= dan;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=1;i<=9;i++) { 
			try {
				Thread.sleep(1500);//1.5초
				System.out.println(dan+"단:"+dan+"*"+i+"="+(dan*i));
			}catch(InterruptedException e) {
				System.out.println(e);
			}
		}//for
	}
}
//Thread 상속
class PrintThread extends Thread{
	@Override
	public void run() {
		// TODO Auto-generated method stub
			for(int i=1;i<=9;i++) {
				try{
				//난수(임의로 만드는 숫자)
				long sleeptime=(int)Math.random()*500+1;//1~500
				System.out.println("sleeptime="+sleeptime);
				Thread.sleep(1500);//sleeptime
				System.out.println("i="+i);
				}
				catch(Exception e) {e.printStackTrace();}
			}
	}
 }
 /*
실행시킬 단?
4
sleeptime=328
i=1
4단:4*1=4
 ...
i=7
sleeptime=60
4단:4*7=28
*/

 


스레드 동기화

한개 이상의 스레드가 하나의 데이터에 대한 작업을 할때 

하나의 스레드가 먼저 일을 다 처리할 동안 다른 스레드는 대기상태로 유지할 수 있도록 해주는 기법

 

동기화 구현하는 방법

1. 메소드명 앞에 syhchronized 키워드를 붙여준다

메소드 자체에 동기화 설정

다른 스레드가 메소드 작업을 하고 있다면 종료할때까지 기다린 후 접근할 수 있다(락을 거는 개념)

import java.io.*;
public class ShareTest implements Runnable{
	RandomAccessFile raf = null;
	
	//Thread를 2개 생성한 후 실행
	public ShareTest() {
		try {
			//경로 포함해서 생성할 파일명, 모드(r,rw)
			//없으면 파일생성, 동일파일 있으면 덮어씀
			raf= new RandomAccessFile("c:/webtest/3.java/result.txt","rw");
	
			//Thread객체를 생성(Runnable객체, 쓰레드명)
			Thread t1 = new Thread(this,"lys");
			Thread t2 = new Thread(this,"test");	
			
			//Thread객체 실행
			t1.start();
			t2.start();		
		}catch(IOException e) {
			System.out.println("파일생성에 오류발생=>"+e);
		}	
	}
	@Override
	public synchronized void run() {
	// TODO Auto-generated method stub
		try {	
			for(int i=0;i<100;i++) {
				raf.writeBytes(Thread.currentThread().getName()+
						"["+i+"]"+raf.getFilePointer()+"\n");
			}
		}catch(Exception e) {
			System.out.println("파일 데이터 출력오류=>"+e);
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//Runnable객체 생성
		new ShareTest();
	}
}

*RandomAccessFile

특정위치에 접근해서 정해진 파일을 생성시켜주는 클래스

getFilePointer() : 파일 포인터위치를 확인할 수 있다

writeBytes(String s) : 파일에 String문자열이 출력된다

 

동기화 전(synchronized 붙이기 전)

작업 순서를 지키지 않고 실행된다

동기화 후

lys 스레드의 start() 작업이 끝난 후 test 스레드가 실행된다

 

2. 메소드 내부에 synchronized 키워드를 이용해서 특정 공유객체를 설정한다

한개 이상의 스레드가 동시에 특정 메소드에 접근은 할 수 있지만, 그 메소드의 특정 부분에는 동시 접근이 안된다

형식) synchronized(공유할데이터){ ,,, }

package j210125;
//급여통장(공유데이터) => ATM(쓰레드 작동)

class ATM implements Runnable{
	private long money=10000;
	
	@Override
	public void run() {//자동이체
		// TODO Auto-generated method stub
		synchronized(this) {//ATM객체
			for(int i=0;i<3;i++) {
				try {
					Thread.sleep(1000);//1초간격
				}catch(Exception e) {}
					if(getMoney()<=0)//if(money<=0)
						break;
					withDraw(2000);
			}//3번을 실시간으로 인출해가는 과정을 보여주기 위함
		}
	}
	//돈을 인출
	public void withDraw(long howmuch) {
		if(money>0) {
			money-=howmuch;
			System.out.println(Thread.currentThread().getName()+","+getMoney());
		}else {
			System.out.println("잔액이 부족합니다");
		}	
	}
	//잔액 조회
	public long getMoney() {
		return this.money;
	}
}

public class SyncTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ATM atm = new ATM();
		Thread t1 = new Thread(atm,"보험금"); //Runnable객체, 쓰레드이름
		Thread t2 = new Thread(atm,"공과금");
		t1.start(); t2.start(); //-> run()-> withDraw()
	}
}
/*
보험금,8000
보험금,6000
보험금,4000
공과금,2000
공과금,0
*/

 

+ Recent posts