독개

쓰레드

by #독개#


Thread

싱글 쓰레드 : main() 만 있을때 (모든 자바프로그램은 JVM이 메인 스레드만들고 메인스레드가 main() 메소드를 실행하면서 시작된다.)

멀티 쓰레드 : 두개 이상의 쓰레드가 동작하는 것



동시성(Concurrency) vs병렬성 (Parallelism)


 Knowledge ] 동시성(Concurrency)과 병렬성(Parallelism)

 

동시성 

병렬성 

용어차이 

논리적 

물리적 

의미 

시에 실행되는 것처럼 보이는것(작업1쪼금->작업2쪼금->작업1쪼금)

실제로 작업이 동시에 처리되는 것 

코어 환경 

싱글코어, 멀티코어에서 가능 

멀티코어에서만 가능 





우선순위

기본적으로 JAVA에서 멀티스레드는 순환 할당 방식(시간으로 너1초 너1초 이런식)을 사용한다.

여러 스레드들의 run()메소드를 조금씩 실행 시키는데 특정 스레드에 우선순위 방식으로 조금더 많이 처리할수 있게 할수있다.


우선순위 변경방법 : thread.setPriority(우선순위)

기본적으로 우선순위5지정 되어있다. 1(낮음)~10(높음)까지 부여가능


사용법

상속 : extends Thread

public class Thread_th extends Thread {

@Override

public void run() {                               //run();을 오버라이딩(재정의)하고

//todo

}

}


public class Main {

public static void main(String[] args) {

Thread_th a = new Thread_th();

   a.start();                                         //실행시킬땐 start();  Thread에 start();메소드안에 run();이 불러오게 되어잇음

}

}



인터페이스: implements Runnable

public class Thread_th implements Runnable {

@Override

public void run() {                             //run();을 오버라이딩(재정의)하고

//todo

}

}


public class Main {

public static void main(String[] args) {

Thread_th a = new Thread_th();        // 이건 Runnable이란 인터페이스를 객체화한거

        Thread b = new Thread(a);              // 우리가 쓸 start();는 Thread클래스 안에있음 그래서 객체화 Thread(Runnable Target)

   b.start();                                       // Thread안에 start();란 메소드가있으니 b.start();

}

}


인터페이스(Runnable)가 필요한 이유는 자바는 다중상속을 지원하지 않기 때문이다.

클래스가 이미 다른 클래스를 상속받고 있다면 Thread클래스 상속 못받지

그럴때 쓰라고 Runnable 인터페이스도 지원함

public class th extends abc implements Runnable {

@Override

public void run() {                              

//todo

  }

}


Thread.sleep((int)(Math.random()*1000));           //괜찮아서 기록


공유객체 : 한개의 객체를 여러 쓰레드에서 사용

공유객체

public class Radio {

public void ch1() {
for(int ct=0 ; ct < 10 ; ct++)
{
System.out.println("채널1입니다.");
}
}
public void ch2() {
for(int ct=0 ; ct < 10 ; ct++)
{
System.out.println("채널2입니다.");
}
}
public void ch3() {
for(int ct=0 ; ct < 10 ; ct++)
{
System.out.println("채널3입니다.");
}
}
}


쓰레드객체

public class Player extends Thread {

Radio rd;
int a;
public Player(int a, Radio rd) {
this.a = a;
this.rd = rd;
}
@Override
public void run() {

switch (a) {
case 1:
rd.ch1();
break;
case 2:
rd.ch2();
break;
case 3:
rd.ch3();
break;
}
}
}


실행

public class Main {

public static void main(String[] args) {

        Radio kk = new Radio();

Player pl = new Player(1,kk);

Player p2 = new Player(2,kk);

Player p3 = new Player(3,kk);


p1.start();

p2.start();

p3.start();

}

}


동기화(synchronized) : 공유객체(동시에 접근)쓸때만 씀


여러 스레드가 하나의 공유객체를 공유해서 사용하다 보면 동시에 접근 했을때 문제되는 부분이 발생한다.

이럴때 하나의 스레드가 공유객체의 한곳에 접근중일때 다른 스레드는 그 스레드의 사용이 끝날때까지 사용하지 못하고 대기하도록

명령하는것이 동기화이다.



메소드 동기화

동기화된 메소드는 동시에 접근할수 없다.

하나의 클래스에서 동기화 된것(동기화메소드,블록)끼리는 동시에 실행할수 없다.

public class Radio {

public synchronized void ch1() {
for(int ct=0 ; ct < 10 ; ct++)
{
System.out.println("채널1입니다.");
}
}
public synchronized void ch2() {
for(int ct=0 ; ct < 10 ; ct++)
{
System.out.println("채널2입니다.");
}
}
public void ch3() {
for(int ct=0 ; ct < 10 ; ct++)
{
 synchronized(this) {
System.out.println("채널3입니다.");
        }
}
}
        public void ch4() {
for(int ct=0 ; ct < 10 ; ct++)
{
System.out.println("채널3입니다.");
}
}

}


말그대로 하나의 쓰레드가 ch1();을 실행중이라면 다른 쓰레드들은 ch2(); , synchronized(this) { }을 실행할수 없다.

ch4();는 가능하다


동기화 블록

메소드에 synchronized를 했을때 단점이 뭘까? 만약에 하나의 메소드가 엄청 길어졌다고 생각해보자.

그럼 하나의 메소드가 끝나야 다음 메소드를 진행하겠지.. 엄청 오래걸리겠지? 실행중인 메소드가 다끝날때까지 기다려야하니

나는 특정 명령에서만 동기화가 되면 된단말야 그래서 이럴때 쓰는것이 동기화 블록이다.


동기화 블록 전까진 T1, T2 동시진입 가능(근본적으로 볼땐 T1 빠르지)

동기화블록에선 먼저 진입한 T1이 처리중이면 , T2는 대기

T1이 동기화블록을 끝내고 나오면 T2는 진입




쓰레드 상태


어떤 쓰레드를 실행대기->실행 으로 해줄지는 CPU의 스케쥴러가 결정한다. 

CPU스케쥴러가 너쪼끔 작업해 하면 실행대기->실행->실행대기 하고 있는다.


run(); 함수를 마치면 쓰레드는 종료가된다. 한번 종료된 쓰레드는 다시 사용하려면 객체를 새로 생성해야한다. 재사용불가

  • BLOCKED : syncronized 에 선진입한 스레드가 먼저 작업할때까지 일시정지

  • WATING : wait()로 대기상태 notify로 풀어줘야함

  • TIME_WATING : sleep()


join : 쓰레드의 실행을 완료 할때까지 기다림

보통 계산작업을 하는 쓰레드의 계산작업을 끝내고 그 결과값을 바탕으로 뭔가 다른일을 진행하려고 할 때 이용

join해둔것만 (메인에서)기다린다.


i2sec.start();

i3sec.start();

i4sec.start();


i2sec.join();

system.out.println("메인스레드종료");


// i2sec이 끝날때까지만 기다리지 나머지 쓰레드는 안기다린다.  즉 2번쓰레드만 종료되면 "메인스레드종료"가 나오고

   3,4 쓰레드는 끝날때까지 동작한다.


다끝날때까지 기다릴려면

i2sec.join();

i3sec.join();

i4sec.join();

해줘야함



데몬쓰레드 : 일반쓰레드 종료되면 알아서 종료

일반쓰레드는 자기가 무조건 종료해야 종료가된다.

데몬쓰레드는 메인메서드+일반쓰레드 즉 모든쓰레드가 다 정지하면 알아서 종료된다. (보통5분마다 저장 이런거 구현할때씀)


run(); 메서드 정의해주는건 같고 구현할때 

Thread a = new Thread();

a.setDaemon(true);                    //이 쓰레드를 데몬쓰레드로 셋팅만해주면됨

a.start();


반환값 

쓰레드에서 값을 전달받으려면? (메소드처럼 리턴값이런개념 안됨!)

run(); 돌면서 리턴받는 방법은없다. 다른방식으로 접근해야함

(공유객체를 통해 리턴받고 메인에서 가져옴 or 쓰레드클래스안의 인스턴스변수로 리턴해서 가져옴or내부메소드만듦)


'🔥 프로그래밍 학습 > JAVA' 카테고리의 다른 글

포트스캐너  (0) 2020.06.03
메소드  (0) 2020.06.02
File 처리/입출력스트림  (0) 2020.05.25
예외처리 try-catch  (0) 2020.05.25
추상화 클래스 , 인터페이스  (0) 2020.05.25

블로그의 정보

독한 개발자

#독개#

활동하기