Thread
Thread의 종류 -UserThread 일반적으로 프로그램에서 만들어지는 Thread Daemon Thread 입출력처리, garbage collection, user Thread구동 등(JVM제공 thread) Daemon Thread Daemon thread-눈에 보이는 화면상으로는 나타나지 않고 백그라운드 형태로 실행되는 프로그램 이다. 전형적으로 같은 application에 있는 object를 위해서 service를 제공하는 독립적인 thread이다. Daemon thread를 위한 run() method는 전형적으로 service의 요청을 기다리며 무한 loop를 수행한다. 주 thread가 종료되면 Daemon Thread는 자동적으로 종료하게 된다. 백그라운드용 Thread라고 알아두면 되겠다. --------- UserThread- 예를 들어 메인메소드에서 만든 사용자쓰레드는 main()이 수행되는 동안 살아 있고 Main()이종료될때 같이 종료된다. 특별한 언급이 없으면 사용자 쓰레드에 관한 사항만 다룬다. ---------- * setDaemon(boolean on)은 반드시 start()를 호출하기 전에 실행되어야 한다. 그렇지 않으면 IllegalThreadStateException이 발생한다. (IllegalStateException : 쓰레드가 요청된 동작에 적합한 상태가 아님을 나타내기 위해 발생) * setDaemon(boolean on)은 반드시 start()를 호출하기 전에 실행되어야 한다. 그렇지 않으면 IllegalThreadStateException이 발생한다.
Thread Group - 서로 관련된 Thread를 그룹으로 묶어서 다루기 위한 것 -모든 Thread는 반드시 하나의 Thread그룹에 포함되어 있어야 한다. - Thread그룹을 지정하지 않고 생성한 Thread는 ‘main Thread그룹’에 속한다. - 자신을 생성한 Thread(조상 Thread)의 그룹과 우선순위를 상속받는다 어플리케이션에서 많은 스레드를 생성해야하는 경우 스레드를 그룹으로 묶어서 관리하는 편이 좀더 편하고 강력할수 있다는 개념에서 만들어 졌지만 java라이브러리중 가장 실패한것 중 하나로 꼽힌다고 합니다. 이유는 그룹안의 스레드를 자유롭게 제어 하기 위한 메소드가 부족하기 때문입니다. 보안 매니져 부분이외에는 스레드 그룹은 거의 사용하지 않는다고 합니다. 그냥 한번 훑어보고 넘어가도 될듯….
작업의 중요도에 따라 Thread의 우선순위를 다르게 하여 특정 Thread가 (priority of thread) 작업의 중요도에 따라 Thread의 우선순위를 다르게 하여 특정 Thread가 더 많은 작업시간을 갖도록 할 수 있다 t(시간) B A ▶ 우선순위가 같은 경우 ▶ A의 우선순위가 높은 경우 t(시간) A B 스레드를 여러 개 운영하는 어플리케이션에서 스레드가 동시에 진행될때 특정 스레드가 먼저 실행되도록 하고 싶을때나, 여러 개의 스레드가 동시에 하나의 공유 인스턴스에 접근할 경우 (이경우 공유객체는 동기화되어 있음으로 오직 스레드 하나만 선점해서 실행할수 있음) 선점할 스레드를 개발자가 지정하고 싶을 때 스레드 우선순위를 지정할수 있음. 스레드 순위는 1부터 10까지 사용할수 있으며 setpriority() 메소드를 사용해서 우선운위를 지정 할 수 있다. 참고로 우리가 기본적으로 생성하는 스레드는 값이 5인 스레드이다.
Thread Thread는 하나의 Process 에서 일을 처리하는 세부 실행단위. default생성자로 Thread객체 생성 일반적으로 java로 기초적인 문제를 작성하거나 프로그램을 만드는 것은 단일 Thread로 동작하는 프로그램. 단일 Thread는 한process에서 하나의 Thread만 가지것인데 반해 multiThread는 하나의 Process를 가지고 동시에 작업을 수행. 1. Thread Class를 상속받는 것. (확장 - Extends) Start() method 호출 run() method 자동으로 호출 실행() 2. Runnable interface 상속.(구현 – Implements) New Thread생성 runnable interface run()작업포함 Thread 시작 run()Method 자동으로 호출 실행() default생성자로 Thread객체 생성 독립적으로 Thread 실행(run()Method 필요) Runnable 인터페이스 구현 객체 생성 후에 Thread의 생성자로 전달 Runnable 인터페이스를 상속 받아 run() Method 작성 스레드의 구현방법은 2가지가 있다. Thread클래스를 상속받는(확잗, extends)이고 두번째 방법은 Runnable인터페이스를 상속받는(구현, implements) 방법이다. 스레드를 실행시키기 위해서는 스레드객체의 start()메소드를 호출함으로써 실행이된다. start()메소소를 호출하면 run()메소드가 자동호출이 되는데, run()메소드는 다중스레드로 동작시키고자하는 내용이 기술되어있다. 그러므로 start()메소드를 사용하면 자동적으로 스레드가 실행된다. 안드로이드는 기본적으로 멀티쓰레드를 잘 지원 한다. 리눅스 자체가 본질적으로 멀티쓰레드 운영체제 이다. *쓰레드와 멀티프로세스의 차이점. 둘다 두가지이상의 작업을 동시에 처리할수 있는 메커니즘이기는 하다. 우선 프로세스는 프로세스를 이루는 몇가지 영역이 있는데 보통 code영역, data영역 , heap영역, stack영역으로 구성이 된다. 이것들이 모여서프로세스를 이루는데 멀티프로세스가 이와같은 프로세스를 통째로 여러개 수행시키는 것이라 한다면 쓰레드는 하나의 프로세스옆에서 프로세스와 같이 수행되는것이 생각하면된다. 쓰레드는 프로세스가 가진 code, data, heap영역을 프로세스와 같이공유한다. 쓰레드는 stack만 따로 가지고 있기 때문이다. 같이 공유하는 영역을 가지다 보니 하나의프로세스에 붙어 있는 여러 쓰레드간 혹은 프로세스와 의 통신에 별다른 부담이 없다. -생성된 쓰레드객체는 그자체가 독립적으로 실행되는 흐름이 된다. 쓰레드는 메인쓰레드와 별도의CPU를 할당 받게 되며 쓰레드를 쓰게 될 경우는 반드시 Run메서드를 작성 해야한다. Thread는 자신이 실행할 메소드, 인자,local 변수를 위한 별도의 callstack을 가진다. 같은 VM내부(안드로이드에서 각각의 어플리케이션은 별도의 VM을 할당 받는다)의 Thread들은 상호작용(interact)이 가능하며, Thread 자신이 제공하는 여러 메소드나 Object로부터 상속하는 여러 객체를 사용해 Thread간의 동기(Synchronization)를 유지할 수 있다 -다중상속이 되지 않기 때문에 다른 클래스를 상속하고 있을 경우 Runnable인터페이스를 상속 받아서 추상화 메서드인 Run메서드를 작성한다. 새로운 쓰레드 생성시 쓰레드 객체의 생성인자로 전달되는 Runnable인터페이스의 run()메소드는 새 쓰레드가 실행할 작업을 포함해야하며 run()은 생성된 새 쓰레드가 시작되면 자동으로 호출된다. 나중에 다시… 한마디로 생성만 시켜주면 자동으로 작동하다 종료하는 작업 ******** Function call stack 이란? 함수 호출 시 기존 함수 정보를 stack에 저장하고 새로운 함수를 호출하는 방법을 말한다. stack에 return address 및 그와 관련된 정보를 넣고, 새로운 함수 수행이 끝나면 기존 함수의 정보를 stack에서 pop하여 기존 함수를 지속적으로 수행한다.
Thread 생성 -default mMainText = (TextView)findViewById(R.id.mainvalue); mBackText = (TextView)findViewById(R.id.backvalue); Button btn = (Button)findViewById(R.id.increase); btn.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { mMainValue++; mMainText.setText("MainValue : " + mMainValue); mBackText.setText("BackValue : " + mBackValue); } }); BackThread thread = new BackThread(); thread.setDaemon(true); thread.start(); class BackThread extends Thread { public void run() { while (true) { mBackValue++; try { Thread.sleep(1000); } catch (InterruptedException e) {;} Thread 생성 -default 두개의 Text를 배치하고 버튼 한나를 배치에 OnclickListener를 구현. 버튼을 클릭하면 main Text가 1일 증하게 함. Thread 객체를 통해서 default생성자로 생성. setDaemon으로 mainThread와 종료동기화. 이후 start() method를 이용 Thread시작. Run()실행 Default생성자로 생성 예제. 종료 동기화는 설명했듯이 메인스레드가 죽으면 서브스레드가 같이 죽어야하는데 그렇지 못하면 메인스레드가 죽어도 서브스레드는 계속돌게 됨.
Thread 생성 -Runnable Runnable 인터페이스 구현. BackRunnable runnable = new BackRunnable(); Thread thread = new Thread(runnable); thread.setDaemon(true); thread.start(); } class BackRunnable implements Runnable { public void run() { while (true) { mBackValue++; try { Thread.sleep(1000); } catch (InterruptedException e) {;} Thread 생성 -Runnable 앞서 선언부와의 내용은 동일함. Thread 객체 인자로 Runnable넣음. 나머지는 동일 Runnable 인터페이스 구현. 선언전 내용은 동일하고 대신 스레드 객체에 인자로 러너블을 넣어 주었슴. 스레드를 구현하는 클래스가 Runnable인터페이스를 구현 한다는것이 다르다. 여기서 Start메소드를 제공하지 않는다 그렇기때문에 Back runnable객체를 타켓으로하여 Thread객체를 먼저 만튼디 Thread.start로 호출 하였다.
Thread 상태 실행을 기다리고 있는 상태는 다음 4가지로 구분 되는데 먼저 waiting은 동기화에 의한 대기상태 이다. Sleep – cpu의 점유를 중지하고 아무것도 하지 않는 상태이다. Suspended – 일시중지상태 Blocked – 입출력 메서드 등의 호출로 인해 메서드의 종료가 일어 날 때까지 대기하는 상태 stop() 에 대해서.. stop() 메서드는 현재 폐기된(Deprecated) 메서드이다. 이 메소드는 안전하지는 않는데, Thread.stop 를 사용해 thread를 강제로 정지를 하면 해당 스레드 뿐만 아니라 다른 대기중인 스레드의 상태를 모호하게 해준다. 이를 모니터의 락을 해제한다고 하는데, 모니터란 실행권한이라고만 우선 알고 있자. 이러한 모니터에 의해 직전까지 보호되고 있던 오브젝트가 보호가 풀린다면 앞으로의 동작을 예측을 할 수가 없다. 즉 스레드간의 일을 서로 미루는 상태인 데드락(Dead Rock)이 걸릴 가능성이 높다. 따라서 이 메서드는 사용하지 않는 것이 좋다. 그럼 stop()메서드를 대처할 메서드는 없는가? 있다. 바로 interrupt() 라는 메서드인데, 이 메서드가 호출되면 스레드에 인터럽트가 예약된다. 인터럽트란 스레드를 중단시키겠다는 뜻으로 아무 때나 중단되지 않기 때문에 일단 예약을 하는 것이다. 예약된 스레드는 계속 실행되다가 sleep() 이나 wait() 메서드들을 만나며 그 즉시 InterruptedException 를 발생시켜 스레드를 중지시킨다. 이 외에도 무한 루프에 걸린 스레드에 어떤 변화 값을 주어 루프를 빠져 나오게 해서 run() 메서드의 실행이 끝나면 스레드도 중지 된다. Method 설명 start() 생성된 쓰레드는 준비(Ready)상태로 들어가서, 쓰레드 스케줄러의 선택을 기다린다.run() 쓰레드가 실행하는 동안 실행할 코드를 갖고 있으며, 쓰레드가 실행(Run)상태에 있는 동안 수행된다. yeild() 다른 쓰레드에게 실행상태를 양보하고, 자신은 준비 상태로 바꾸는 쓰레드이다. sleep() 쓰레드는 실행 상태에서 슬립상태로 드러간다. 쓰레드가 일정시간 잠자는 것이다. 지연(Blocked) 쓰레드가 입출력과 관련된 메서드를 호출할 때, 이 메서드가 완료될 때까지 쓰레드가 들어가 있는 상태이다.(입출력은 속도가 느리다.그래서....) 대기(Waiting) wait() 메서드에 의해서 특정 이벤트를 기다리는 상태이다. 여러 쓰레드가 개입된 동기화 코드 내에서만 쓰레드에 의해 호출이 가능하고, 다른 쓰레드의 notify()메서드에 의해서만 깨워질 수 있다.즉, 특정 자원을 점유하기 위해, 다른 쓰레드와의 동기화에 의한 관계 때문에 변화되는 상태이다.
한 번에 하나의 Thread만 객체에 접근할 수 있도록 객체에 락(lock)을 걸어서 데이터의 일관성을 유지하는 것. Thread Synchronized 한 번에 하나의 Thread만 객체에 접근할 수 있도록 객체에 락(lock)을 걸어서 데이터의 일관성을 유지하는 것. 스레드는 별로도 실행되는 하나의 흐름인데 동시에 여러 개의 스레드가 실행되면 스레드들이 공유하는 자원에 대한 동기화 문제가 발생 한다. 락은 어떤 객체에 여러 스레드가 동시에 접근하지 못하도록 하기위한 것으로 모든객체가 인스턴스화 될때 (힙영역에 객체가 저장될때) 자동으로 생선된다. 이렇게 생성되 락은 보통의 경우 사용되지 않고 동기화가 필요한 부분에서 락을 사용하기 위해서는 바로 synchronized 키워드를 사용해야 한다. 한마디로 한 번에 하나의 쓰레드만 객체에 접근할 수 있도록 객체에 락(lock)을 걸어서 데이터의 일관성을 유지하는 것. 어떤 클래스를 new키워드로 인스턴스화 하면 락과 함께 모니터라는것이 자동 생성된다. 이모니터는 락의 현재 사용여부를 검사함으로써 각객체를 보호해주는 역할을 한다. 만약 어떤스레드가 synchronized를 사용한 메소드나 블록에 접근 하게되면 그 synchronized와 연관된 모니터는 해당 객체의 레퍼런스를 검사한다. 이때 락이 아직 다른 어떤스레드에게 사용되지 않고 있다면 JVM에세 알려준다. 그러면 jvm은 monitorenter라는 JVM내부 명형을 해당객체의 락을 요청한 스레드에게 준다. 반대로 락이 다른 어떤 스레드에 의해 사용되고 있다면 락이 반환 될때까지 더 이상 진행되지 않고 그스레드는 대기하게 된다. 스레드가 락을 얻은 후에 synchronized는 메소드나 블록을 마치고 나면 moniteorexit라는 JVM내부 명령을 자동으로 실행해서 해당 스레드가 얻은 객체의 락을 즉시 반환한다. Method에 선언 Block형태 사용
END