자바 스 레 드 탱크 원리 깊이 분석
Executor 프레임 워 크 의 2 단계 스케줄 링 모델
HotSpot VM 모델 에서 자바 스 레 드 는 로 컬 운영 체제 스 레 드 로 일대일 매 핑 됩 니 다.JAVA 스 레 드 가 시 작 될 때 로 컬 운영 체제 스 레 드 를 만 듭 니 다.JAVA 스 레 드 가 종 료 될 때 해당 하 는 운영 체제 스 레 드 도 폐기 되 고 회수 되 며 운영 체 제 는 모든 스 레 드 를 예약 하여 사용 가능 한 CPU 에 배정 합 니 다.
상층 부 에 서 는 JAVA 프로그램 이 여러 작업 으로 분 해 된 다음 응용 급 스케줄 러(Executor)를 사용 하여 이 작업 을 고정된 수량의 스 레 드 로 표시 합 니 다.바 텀 에서 운영 체제 커 널 은 이 스 레 드 를 하드웨어 프로세서 에 투사 한다.
Executor 프레임 워 크 클래스
앞서 소 개 된 JAVA 스 레 드 는 작업 단원 이자 실행 메커니즘 이다.Executor 프레임 워 크 에서 우 리 는 작업 단원 과 집행 메커니즘 을 분리 한다.Runnable 과 Callable 은 작업 단원(즉 속칭 임무)이 고 실행 메커니즘 은 Executor 가 제공한다.이렇게 되면 Executor 는 생산자 소비자 모델 을 바탕 으로 임 무 를 제출 하 는 조작 은 생 성자 에 해당 하고 임 무 를 수행 하 는 라인 은 소비자 에 해당 한다.
1.아 날로 그 에서 볼 때 Executor 인 터 페 이 스 는 비동기 작업 수행 프레임 워 크 의 기초 이 고 이 프레임 워 크 는 다양한 유형의 작업 수행 전략 을 지원 할 수 있 습 니 다.
public interface Executor {
void execute(Runnable command);
}
Executor 인 터 페 이 스 는 실행 방법 을 제공 합 니 다.작업 은 Runnbale 형식 이 고 Callable 형식 은 지원 되 지 않 습 니 다.2.ExecutorService 인 터 페 이 스 는 Executor 인 터 페 이 스 를 실현 하고 주로 스 레 드 풀 과 submit 를 닫 는 방법 을 제공 합 니 다.
public interface ExecutorService extends Executor {
List<Runnable> shutdownNow();
boolean isTerminated();
<T> Future<T> submit(Callable<T> task);
}
또한 이 인 터 페 이 스 는 두 가지 중요 한 실현 유형 이 있 는데 그것 이 바로 Thread PoolExecutor 와 Scheduled Thread PoolExecutor 이다.그 중에서 Thread PoolExecutor 는 스 레 드 탱크 의 핵심 실현 클래스 로 제출 된 작업 을 수행 합 니 다.한편,Scheduled Thread PoolExecutor 는 실행 클래스 로 주어진 지연 후에 작업 을 실행 하거나 정기 적 으로 명령 을 수행 할 수 있 습 니 다.
이전 글 에서 저 는 Thread PoolExecutor 를 사용 하여 서로 다른 파 라 메 터 를 지정 하여 필요 한 스 레 드 풀 을 만 들 었 습 니 다.그러나 뒤의 작업 에서 이런 방식 을 권장 하지 않 습 니 다.Exectuors 공장 방법 으로 스 레 드 풀 을 만 드 는 것 을 추천 합 니 다.
먼저 스 레 드 탱크 와 스 레 드 그룹(ThreadGroup 과 ThreadPoolExecutor)이라는 두 개념 을 구별 합 니 다.
a.스 레 드 그룹 은 하나의 스 레 드 의 집합 을 나타 낸다.
b.스 레 드 탱크 는 스 레 드 의 생명 주기 비용 문제 와 자원 부족 문제 에 해결 방안 을 제공 하 는 것 으로 주로 스 레 드 를 관리 하 는 데 사용 된다.
Executors 는 3 가지 유형의 ThreadPoolExecutor:SingleThreadExecutor,Fixed ThreadExecutor,CachedThreadPool 을 만 들 수 있 습 니 다.
a,SingleThreadExecutor:단일 라인 스 레 드 탱크
ExecutorService threadPool = Executors.newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
원본 코드 를 보면 알 수 있 듯 이 단선 스 레 드 탱크 의 생 성 도 Thread PoolExecutor 를 통 해 이 루어 집 니 다.그 안의 핵심 스 레 드 수 와 스 레 드 수 는 모두 1 이 고 작업 대기 열 은 무한 대기 열 을 사용 합 니 다.단일 스 레 드 작업 이기 때문에 매번 하나의 작업 만 처리 할 수 있 기 때문에 뒤의 모든 작업 은 작업 대기 열 에 막 혀 하나의 작업 만 수행 할 수 있 습 니 다.b.FixedThreadExecutor:고정 크기 스 레 드 탱크
ExecutorService threadPool = Executors.newFixedThreadPool(5);
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
이것 은 단일 스 레 드 와 유사 합 니 다.고정 크기 의 스 레 드 수 를 만 들 었 을 뿐 입 니 다.c,CachedThreadPool:무한 스 레 드 탱크
ExecutorService threadPool = Executors.newCachedThreadPool();
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
무 계 스 레 드 탱크 는 작업 대기 열 이 없 으 면 작업 이 들 어 오 면 실행 되 고 스 레 드 수량 이 부족 하면 만 드 는 것 을 의미 합 니 다.앞의 두 가지 차이 점 은 남 은 스 레 드 는 회수 되 고 남 은 시간 은 60s 입 니 다.이것 은 단기 비동기 프로그램 을 많이 실행 하거나 부하 가 가 벼 운 서버 에 적용 된다.Callable,Future,FutureTash 상세 설명
Callable 과 Future 는 JAVA 의 후속 버 전에 서 도입 되 었 습 니 다.Callable 은 Runnable 인터페이스 와 유사 하고 Callable 인 터 페 이 스 를 실현 하 는 클래스 와 Runnable 을 실현 하 는 클래스 는 모두 스 레 드 로 실 행 될 수 있 는 작업 입 니 다.
삼자 간 의 관계:
Callable 은 Runnable 에 포 장 된 비동기 연산 작업 입 니 다.
Future 는 Callable 비동기 연산 결 과 를 저장 합 니 다.
Future Task 패키지 Future 의 실체 클래스
1.Callable 과 Runnbale 의 차이
a.Callable 이 정의 하 는 방법 은 call 이 고 Runnable 이 정의 하 는 방법 은 run 입 니 다.
b.call 방법 은 반환 값 이 있 고 run 방법 은 반환 값 이 없습니다.
c.call 방법 은 이상 을 던 질 수 있 지만 run 방법 은 이상 을 던 질 수 없습니다.
2、Future
Future 는 비동기 계산 결 과 를 나타 내 는데 다음 과 같은 방법 을 제공 했다.주로 임무 의 완성 여 부 를 판단 하고 임 무 를 중단 하 며 임무 수행 결 과 를 얻 는 것 이다.
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
3、FutureTask취소 가능 한 비동기 계산 은 Future 에 대한 기본 적 인 실현 을 제공 합 니 다.계산 이 완료 되 었 을 때 만 결 과 를 얻 을 수 있 습 니 다.계산 이 완료 되 지 않 으 면 get 방법 을 차단 합 니 다.
public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V>
Future Task 는 Future 인터페이스 뿐만 아니 라 Runnable 인터페이스 도 실현 하기 때문에 Future Task 를 하나의 임무 로 Executor 에 맡 길 수 있 을 뿐만 아니 라 Thread 를 통 해 스 레 드 를 만 들 수 있 습 니 다.Callable 과 Future Task
callable 작업 정의:
public class MyCallableTask implements Callable<Integer>
{
@Override
public Integer call()
throws Exception
{
System.out.println("callable do somothing");
Thread.sleep(5000);
return new Random().nextInt(100);
}
}
public class CallableTest
{
public static void main(String[] args) throws Exception
{
Callable<Integer> callable = new MyCallableTask();
FutureTask<Integer> future = new FutureTask<Integer>(callable);
Thread thread = new Thread(future);
thread.start();
Thread.sleep(100);
//
future.cancel(true);
//
System.out.println("future is cancel:" + future.isCancelled());
if(!future.isCancelled())
{
System.out.println("future is cancelled");
}
//
System.out.println("future is done:" + future.isDone());
if(!future.isDone())
{
System.out.println("future get=" + future.get());
}
else
{
//
System.out.println("task is done");
}
}
}
실행 결과:
callable do somothing
future is cancel:true
future is done:true
task is done
이 DEMO 는 주로 Future Task 의 상태 설정 을 호출 하 는 방법 으로 상태의 변 화 를 보 여 줍 니 다.a.11 번 째 줄 에서 작업 수행 을 취소 하려 고 시도 합 니 다.이 방법 은 작업 이 완료 되 었 고 취소 되 었 으 면 false 로 돌아 갑 니 다.아직 완성 되 지 않 은 작업 을 취소 할 수 있다 면 true 로 돌아 갑 니 다.이 DEMO 에 서 는 작업 이 휴면 상태 이기 때문에 취소 할 수 있 습 니 다.
future.cancel(true);
b.제1 3 줄,퀘 스 트 취소 성공 여 부 를 판단 합 니 다.퀘 스 트 가 정상적으로 완성 되 기 전에 취소 하면 true 로 돌아 갑 니 다.
System.out.println("future is cancel:" + future.isCancelled());
c.제1 9 행,임무 의 완성 여 부 를 판단 합 니 다.만약 에 임 무 를 완성 하면 true 로 돌아 갑 니 다.다음 과 같은 몇 가지 상황 은 모두 임무 완성 에 속 합 니 다.정상 적 인 종료,이상 또는 취소 로 완성 합 니 다.우리 의 데모 에서 임 무 는 취소 로 인해 완성 되 었 다.
System.out.println("future is done:" + future.isDone());
d.22 번 째 줄 에서 비동기 스 레 드 가 실 행 된 결 과 를 얻 습 니 다.저 는 이 DEMO 에서 여기까지 실행 되 지 않 았 습 니 다.주의해 야 할 것 은 future.get 방법 은 현재 스 레 드 를 막 고 작업 이 실 행 될 때 까지 결 과 를 되 돌려 줄 것 입 니 다.
System.out.println("future get=" + future.get());
Callable 과 Future
public class CallableThread implements Callable<String>
{
@Override
public String call()
throws Exception
{
System.out.println(" Call , , :" + System.currentTimeMillis());
Thread.sleep(10000);
return " ";
}
public static void main(String[] args) throws Exception
{
ExecutorService es = Executors.newSingleThreadExecutor();
Callable<String> call = new CallableThread();
Future<String> fu = es.submit(call);
es.shutdown();
Thread.sleep(5000);
System.out.println(" 5 , " + System.currentTimeMillis());
String str = fu.get();
System.out.println("Future ,str=" + str + "; :" + System.currentTimeMillis());
}
}
실행 결과:
Call , , :1478606602676
5 , 1478606608676
Future ,str= ; :1478606612677
이곳 의 future 는 스 레 드 탱크 에 직접 던 져 서 실 행 했 습 니 다.작업 의 실행 결 과 를 인쇄 해 야 하기 때문에 실행 결 과 를 보면 메 인 스 레 드 는 5s 휴면 을 했 지만 Call 방법 에서 작업 의 결 과 를 얻 을 때 까지 중간 시간 차 는 10s 입 니 다.get 방법 은 작업 이 완 료 될 때 까지 현재 스 레 드 를 막 을 수 있 음 을 설명 합 니 다.Future Task 를 통 해서 도 같은 효 과 를 얻 을 수 있 습 니 다:
public static void main(String[] args) throws Exception
{
ExecutorService es = Executors.newSingleThreadExecutor();
Callable<String> call = new CallableThread();
FutureTask<String> task = new FutureTask<String>(call);
es.submit(task);
es.shutdown();
Thread.sleep(5000);
System.out.println(" 5 , :" + System.currentTimeMillis());
String str = task.get();
System.out.println("Future ,str=" + str + "; :" + System.currentTimeMillis());
}
이상 의 조합 은 우리 에 게 이러한 변 화 를 가 져 다 줄 수 있다.만약 에 한 장면 에서 방법 A 가 한 데 이 터 를 되 돌려 주 려 면 10s 가 필요 하고 A 방법 뒤의 코드 운행 은 20s 가 필요 하지만 이 20s 의 실행 과정 에서 뒤의 10s 만 방법 A 가 실행 한 결과 에 의존한다.예전 과 같이 동기 화 방식 을 사용 하면 반드시 10s 의 시간 이 낭비 되 고 앞의 두 가지 조합 을 사용 하면 효율 이 높아진다.
1.먼저 A 방법의 내용 을 Callable 실현 류 의 call()방법 에 넣 습 니 다.
2.메 인 스 레 드 에서 스 레 드 풀 을 통 해 A 작업 수행
3,실행 후 방법 중 10 초 방법 A 실행 결과 에 의존 하지 않 는 코드
4.방법 A 의 실행 결 과 를 얻 고 다음 방법 중 10 초 의존 방법 A 실행 결과 의 코드 를 실행 합 니 다.
이렇게 코드 의 집행 효율 이 단번에 높 아 졌 으 니 프로그램 은 A 방법 에 걸 릴 필요 가 없다.
읽 어 주 셔 서 감사합니다. 여러분 에 게 도움 이 되 기 를 바 랍 니 다.본 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.