자바 스레드와 비동기처리

 

 

main도 GC도 Thread로 동작
(가비지컬렉터는 우선 순위가 낮고 동적 할당된 메모리를 수거하는 보조적인 업무를 하는 데몬스레드)

 

프로세스 context 스위칭 fork() 

(하나의 프로세스가 자식 프로세스를 만들어 다른 프로그램의 cpu 리소스를 빼먹어 성능저하와 형평성문제 발생

=> 스레드 context 스위칭 

(프로세스에 cpu가 리소스를 할당하고 그 후 해당 프로세스에서 thread에 할당 받은 리소스를 나누어 주어 형평성 문제를 해결)
(데이터와 힙 메모리 영역을 프로세스와 자식 스레드들이 공유하고 스레드는 스택과 포인터 영역만을 지역스코프처럼 사용하기 때문에 동일 프로세스 내 스레드끼리 데이터 공유가 쉽다. 프로세스 context 스위칭의 경우 다른 프로그램이므로 데이터 공유가 어려웠다) 

 

동기형 - 순차적 진행
비동기형 - 동시진행(할당된 리소스(시간분배 등)을 중간중간 빠른 속도로 전환하며 진행)

 

 

Thread 객체에 필요한 Runnable 인터페이스 객체


Thread th1 = new Thread(Runnable);


인터페이스는 익명함수로 객체 구현이 가능하다

(일회성의 구현 객체를 위해 소스 파일을 만들고 클래스를 선언하는것은 비효율적)
인터페이스이므로 인터페이스 명세에서 요구하는 메소드는 구현해줘야 한다. run()
Thread th1 = new Thread(new Runnable() {
    public void run() {
      func();
    }
  });
th1. start();

일회성이 아니라면 Runnable을 빼서 따로 오버라이드 해준다

 


스레드 시작 객체&메서드
Thread, Runnable, Runnable.run(), Thread.start()

 


자주 쓰는 스레드의 속성&메서드
Thread.sleep() // 밀리초(long millis) 입력.
Thread th = Thread.currentThread(); // 사용 중인 현재 쓰레드
th.getId()  // 식별자 가져오기
th.getName() // 이름 가져오기
th.setName() // 이름 지정
th.getPriority() // 0~10 우선순위. 숫자가 클수록 우선순위 높음. 기본 5.
th.setPriority() // 우선순위 설정. 
th.setDaemon(boolean) // 유령스레드 설정 토글. 데몬스레드(업무가 없다, 다른 스레드를 도우는 스레드, 다른 스레드가 종료되면 함께 종료됨 ex_가비지컬렉터)
th.getState() // 현재 상태 확인. Timed waiting | runnable | terminated 등등... 대문자 String으로 반환하므로 조건문에 사용
생성 되었을 때 NEW, 스레드 실행 중 RUNNABLE, sleep 등으로 인한 대기중 TIMED_WATING, 작업 종료 TERMINATED
th.join(); // 우선적으로 작업이 끝나도 해당 스레드의 작업 종료를 기다림. milliSceond 를 인자로 줘 기다리는 시간을 지정할 수 있다
th.isAlive() // 해당 스레드가 작업중인지 boolean 값으로 리턴
th.interrupt() // 해당 스레드에 종료 요청을 보냄. 예외처리 InterruptedException에 걸리지만 종료는 되지 않는다.
th.isInterrupted() // 중지 요청을 받았는지 boolean 값으로 리턴

스레드 그룹 객체
ThreadGroup thGroup = new ThreadGroup("GroupName"), 첫번째 인자로 그룹네임이 아닌 다른 그룹을 줄 경우 계층 형성
// 스레드 생성 시 그룹 설정 가능 new Thread(thGroup, Runnable)

그룹 메서드
thGroup.list(); // 스레드name, priority, groupname 출력
thGroup.activeCount();
thGroup.activeGroupCount();  // 활성화 중인 스레드, 하위 그룹 갯수확인


Critical Section (임계영역) & Monitor Lock
(스레드는 부모 프로세스의 데이터, 힙 영역을 공유하기에 전역변수와 같은 데이터 영역에 올라가는 것을 동시에 끌어다 쓰면 문제가 발생한다. 이를 방지하기 위해 임계영역을 정해 해당부분은 Object나 this와 같은 어떠한 객체가 없으면 기다렸다가 들어가야 하거나, 되돌리는 등으로 구현해줄 수 있다) 

 


임계영역에 락을 거는 방법


synchronized(잠금객체)

{임계영역 코드}

public synchronized void function()

{임계영역 코드}

메소드 단위 동기화(성능에 큰 영향이 있으므로 권장되지 않음)

ReentrantLock indexLock = new ReentrantLock(); 

// 잠금객체 부분에 Object, this 대신 사용하거나 아래와 같이 사용한다
indexLock.lock();
임계영역 코드
indexLock.unlock();

또는
indexLock.tryLock(); // boolean 반환
// 조건문을 활용해 먼저 진입해 잠겨진 임계영역에 다른 스레드가 도달할 시 대기하지 않고 진행하게 할 수 있다

 


임계영역이 여러 곳일 때


ReentrantReadWriteLock listLock  = new ReentrantReadWriteLock (); 
listLock.writeLock().lock();
임계영역 코드
listLock.writeLock().unlock();
listLock.readLock().lock();
임계영역 코드
listLock.readLock().unlock();


writeLock은 하나의 스레드만 소유 가능하고 readLock은 동시에 여러 스레드가 소유 가능하다
writeLock이 잠기면 readLock을 소유한 스레드도 임계영역에 들어갈 수 없다
writeLock이 풀리면 readLock은 서로를 동기화 시키지 않고(대기하지 않고) 한꺼번에 진행된다

'Development > Java' 카테고리의 다른 글

Servlet #1  (0) 2022.08.11
Tomcat  (0) 2022.08.11
JDBC  (0) 2022.08.07
JAVA Collection & Generic  (0) 2022.08.04
이클립스에서 GitHub contribution 안되는 문제  (0) 2022.08.02

+ Recent posts