JAVA

스레드(Thread)

choi121xx 2014. 9. 12. 15:09

 

1. 스레드(Thread) 


- 하나의 응용프로그램에서 여러개의 작업을 경량의 프로세스로 나누어 실행하는것


- 시간이 오래지연되는 작업이나,동시에 실행되어야 하는 작업이 있을때 스레드로 만든다.

 예) 파일복사하기(시간이지연되는작업), 파일다운로드받기(동시에다운받기)

     프린터로출력하기,게임프로그램에서 이미지를동시에이동하기,...


- 만드는 방법


방법1) Thread클래스를 상속받아 만들기

     - Thread클래스를 상속받아 run메소드를 오버라이딩한다.

       스레드를 실행할때는 start메소드를 사용한다.


방법2) Runnable인터페이스를 상속받아 만들기



ex>1.스레드클래스 상속받아 만들기.

package test02.thread;

//방법1)

//1.스레드클래스 상속받기

class MyPrinter extends Thread{

    //2.run메소드 오버라이딩하기

    public void run(){

        for(int i=1;i<=1000;i++){

            System.out.print("프린터로 출력중.....");

            if(i%10==0) System.out.println();

        }

    }

}

public class Test01_Thread {

    public static void main(String[] args){

        //스레드객체 생성하기

        MyPrinter mp=new MyPrinter();


        //스레드로 구동하기==>start메소드가 

        // 내부적으로 run메소드호출

        mp.start();


        //printer();

        for(int i=1;i<=1000;i++){

            System.out.print("문서작업중.....");

            if(i%10==0) System.out.println();

        }

    }

    /-

    public static void printer(){

        for(int i=1;i<=1000;i++){

            System.out.print("프린터로 출력중.....");

            if(i%10==0) System.out.println();

        }

    }*-

}

 


ex>

package test02.thread;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.util.Scanner;

public class Test02_Thread{


    public static void main(String[] args){


        Scanner scan=new Scanner(System.in);


        while(true){

            System.out.println("1.파일복사 2.디렉토리크기 3.종료");

            int n=scan.nextInt();

            switch(n){

                case 1:filecopy();break;

                case 2:long size=getSize(new File("c:\\java"));

                       System.out.println("디렉토리크기:" + size +"bytes");

                       break;

                case 3:System.exit(0);

            }

        }

    }


    //파일복사하는 기능

    public static void filecopy(){

        try{

            FileInputStream fis=new FileInputStream("c:\\java\\java.exe");

            FileOutputStream fos=new FileOutputStream("c:\\java\\copy.exe");

            byte[] b=new byte[50];

            int n=0;

            while((n=fis.read(b))!=-1){

                fos.write(b,0,n);

            }

            fos.close();

            fis.close();

            System.out.println("[[[[[[[[[  파일복사성공!!!!   ]]]]]]]]]]]]");

        }catch(IOException ie){

            System.out.println(ie.getMessage());

        }

    }

    public static long getSize(File f){

        long size=0;

        File list[]=f.listFiles();

        for(File ff:list){

            if(ff.isFile()){

                size+=ff.length();

            }else{

                size+=getSize(ff);

            }

        }

        return size;

    }

}

 

 

 

ex>

package test02.thread;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.util.Scanner;


class FileCopyThread extends Thread{

    public void run(){

        try{

            FileInputStream fis=new FileInputStream("c:\\java\\java.exe");

            FileOutputStream fos=new FileOutputStream("c:\\java\\copy.exe");

            byte[] b=new byte[50];

            int n=0;

            while((n=fis.read(b))!=-1){

                fos.write(b,0,n);

            }

            fos.close();

            fis.close();

            System.out.println("[[[[[[[[[  파일복사성공!!!!   ]]]]]]]]]]]]");

        }catch(IOException ie){

            System.out.println(ie.getMessage());

        }

    }

}

public class Test03_Thread {

    public static void main(String[] args) {

        Scanner scan=new Scanner(System.in);

        while(true){

            System.out.println("1.파일복사 2.디렉토리크기 3.종료");

            int n=scan.nextInt();

            switch(n){

                case 1:FileCopyThread thread=new FileCopyThread();

                       thread.start();

                       break;

                case 2:long size=getSize(new File("c:\\java"));

                       System.out.println("디렉토리크기:" + size +"bytes");

                       break;

                case 3:System.exit(0);

            }

        }    

    }

    

    public static long getSize(File f){

        long size=0;

        File list[]=f.listFiles();

        for(File ff:list){

            if(ff.isFile()){

                size+=ff.length();

            }else{

                size+=getSize(ff);

            }

        }

        return size;

    }

}

 

 


ex> 방법2 >>

package test02.thread;

//1. Runnable 인터페이스 상속받기

class FileCopy implements Runnable{

    //2. run메소드 오버라이딩하기

    public void run() {

        for(int i=1;i<=100;i++){

            System.out.println("파일복사중...");

            try{

                //스레드를 1초동안 지연시키기

                Thread.sleep(1000);

            }catch(InterruptedException ie){

                System.out.println(ie.getMessage());

            }

            if(i%10==0) System.out.println();

        }

        System.out.println("파일복사완료!!!!");

    }

}

public class Test04_Runnable {


    public static void main(String[] args) {    

        //3. Runnable자식객체 생성

        FileCopy fc=new FileCopy();


        //4. Thread클래스를 이용해서 스레드로 구동시키기

        Thread th=new Thread(fc);


        th.start();

        //new Thread(fc).start();


        for(int i=1;i<=100;i++){

            System.out.println("문서작업중...");

            try{

                Thread.sleep(1000);//1초동안 스레드 지연시키기

            }catch(InterruptedException ie){

                System.out.println(ie.getMessage());

            }

            if(i%10==0) System.out.println();

        }

    }

}





ex>  1초에 한번씩 현재 시간을 얻어와 출력하는 스레드와

1초에 한번씩 난수를 얻어와 출력하는 스레드를 만들고 실행시켜 보세요.


package test02.thread;

import java.util.Calendar;

import java.util.Random;


class TimeThread extends Thread{

    public void run() {

        while(true){

            Calendar cal=Calendar.getInstance();

            String t=cal.get(Calendar.HOUR_OF_DAY) + "시" +

                     cal.get(Calendar.MINUTE) +"분" +

                     cal.get(Calendar.SECOND) +"초";

            System.out.println(t);

            try{

                Thread.sleep(1000);

            }catch(InterruptedException ie){

                System.out.println(ie.getMessage());

            }

        }

    }

}

class RndThread implements Runnable{

    public void run(){

        Random rnd=new Random();

        while(true){

            int n=rnd.nextInt(100);

            System.out.println("난수:"+ n);

            try{

                Thread.sleep(1000);

            }catch(InterruptedException ie){

                System.out.println(ie.getMessage());

            }

        }

    }

}

public class Quiz01 {

    public static void main(String[] args) {

        //TimeThread tt=new TimeThread();

        //tt.start();

        new TimeThread().start();

        new Thread(new RndThread()).start();

    }

}



 

ex> Message.java

package test01.thread;
//스레드간에 공유하게 될 클래스
public class Message {
    private String msg="";
    public boolean status=false;
    public void setMsg(String msg){
        this.msg+=msg;
    }
    public String getMsg(){return msg;}
}

Test01_useMsg.java
package test01.thread;
class ReadThread extends Thread{
    private Message msg;
    public ReadThread(Message msg){
        this.msg=msg;
    }
    public void run(){
        for(char a='A';a<='Z';a++){
            msg.setMsg(String.valueOf(a));
        }
        System.out.println("Message객체에 저장 완료!");
    }
}
class WriteThread extends Thread{
    private Message msg;
    public WriteThread(Message msg){
        this.msg=msg;
    }
    public void run(){
        System.out.println("다운로드된 데이터를 출력합니다.");
        System.out.println(msg.getMsg());
    }
}
public class Test01_useMsg {
    public static void main(String[] args) {
        Message msg=new Message();//공유자원이 될 객체
        //스레드생성하기
        ReadThread rt=new ReadThread(msg);
        WriteThread wt=new WriteThread(msg);
        //스레드 구동하기(start메소드로 스레드 구동!!!)
        rt.start();
        wt.start();
    }
}
 
 
 


[ 스레드의 동기화 ]
- 하나의 자원(객체)을 여러개의 스레드가 공유해서 사용할때 하나의 스레드가 객체를 사용중이면 다른 스레드는 사용할 수 없으며 락(lock)을 걸어두는것.
- 동기화처리방법

  방법1) 
  동기화해야할 객체를 synchronized블록으로 묶기
   synchronized(공유객체){
   ...
   }

   방법2)
  동기화될 객체 자체에서 동기화 처리하기-동기화메소드로 만들기
   public synchronized 리턴형 메소드명(매개변수,..){
   ..
   }

ex2> 동기화처리 방법2) 공유자원 객체 자체에서 동기화 처리하기(동기화메소드)
Message.java
package test02.sync;
//스레드간에 공유하게 될 클래스
//동기화처리 방법2) 공유자원 객체 자체에서 동기화 처리하기(동기화메소드)
public class Message {
    private String msg="";
    private boolean status=false;
    public synchronized void setMsg(String msg){
        for(int i=0;i<100000000;i++);//시간지연
        this.msg+=msg;
        status=true;//작업이 완료됨을 표시
        notify();//wait()로 대기중인 객체를 깨움
    }
    public synchronized String getMsg(){
        if(status==false){//아직 임시저장소에 저장하는 작업이 완료되지 않았다면
            try{
                wait();//notify()로 신호가 올때까지 대기상태가 됨
            }catch(InterruptedException ie){}
        }
        return msg;
    }
}

Test02_synchronized.java
package test02.sync;
import test01.thread.Message;

class ReadThread extends Thread{
    private Message msg;
    public ReadThread(Message msg){
        this.msg=msg;
    }
    public void run(){
        //공유자원객체(msg)를 synchronized 블록으로 묶기
        //블록이 끝날때까지 다른 스레드는 msg를 사용하지 못하고 대기상태가 된다.
        synchronized (msg) {
            System.out.println("임시저장소에 데이터를 저장하기 시작!");
            for(char a='A';a<='Z';a++){
                msg.setMsg(String.valueOf(a));
                for(int i=1;i<=1000000000;i++);//시간지연하기
            }
            System.out.println("Message객체에 저장 완료!");
            msg.status=true;//작업이 완료됨을 표시
            msg.notify();//wait중인 다른 스레드를 깨움.
        }
    }
}
class WriteThread extends Thread{
    private Message msg;
    public WriteThread(Message msg){
        this.msg=msg;
    }
    public void run(){
        synchronized(msg){
            if(msg.status==false){//임시저장소에 저장하는 작업이 아직 안끝났으면
                try{
                    msg.wait();//notify로 신호가 올때까지 대기하기
                }catch(InterruptedException ie){
                    System.out.println(ie.getMessage());
                }
            }
            System.out.println("다운로드된 데이터를 출력합니다.");
            System.out.println(msg.getMsg());
        }
    }
}
public class Test02_synchronized {
    public static void main(String[] args) {
        Message msg=new Message();//공유자원이 될 객체
        ReadThread rt=new ReadThread(msg);
        WriteThread wt=new WriteThread(msg);
        rt.start();
        wt.start();
    }
}


Test03_synchronized.java
package test02.sync;
class ReadThread1 extends Thread{
    private Message msg;
    public ReadThread1(Message msg){
        this.msg=msg;
    }
    public void run(){
        msg.setMsg("아리랑");
        System.out.println("Message객체에 저장 완료!");
    }
}
class WriteThread1 extends Thread{
    private Message msg;
    public WriteThread1(Message msg){
        this.msg=msg;
    }
    public void run(){
        System.out.println("다운로드된 데이터를 출력합니다.");
        System.out.println(msg.getMsg());
    }
}
public class Test03_synchronized {
    public static void main(String[] args) {
        //공유자원객체 생성
        Message obj=new Message();
        //스레드 실행하기
        new ReadThread1(obj).start();
        new WriteThread1(obj).start();
    }
}


Test04_ThreadStop.java
package test02.sync;
class MyThread extends Thread{
    private boolean stop=true;
    public void setStop(boolean stop){
        this.stop=stop;
    }
    @Override
    public void run() {
        while(stop){
            System.out.println("1.스레드로 작업수행중!");
            System.out.println("2.스레드로 작업수행중!");
            System.out.println("3.스레드로 작업수행중!");
            System.out.println("스레드로 작업완료!");
        }
    }
}
public class Test04_ThreadStop {
    public static void main(String[] args) {
        MyThread th=new MyThread();
        th.start();
        try{
            //2초후 스레드 지연하기
            Thread.sleep(2000);
        }catch(InterruptedException ie){
            System.out.println(ie.getMessage());
        }
        th.setStop(false);//스레드 멈추기
    }
}