자바 스레드 생성자 멀티 스레딩 (소스 코드 분석)

스레드의 수명주기와 공통점 API의 상태에 이전 기사에서 우리는 해설자가 있었다. 이 문서의 구축 방법에 대한 설명에 집중되기 시작했다 우리가 시작 방법은 스레드를 시작할 수 있습니다 부르는 이유, 그것은 또한 발표 될 예정이다.

첫째, 데몬 스레드 및 비 데몬 스레드

우리는 스레드를 실행하는 자바 가상 머신이 될 때 기본이 우리의 서비스에 대한 스레드 몇 가지 다른 스레드를 시작하기 때문입니다, 스레드 ID는 모든 시간이 0이 아닌 시간을 찾을 수. 그리고 기본적으로 생성 된 스레드는 구별이 우리 자신의 만들 수 있습니다. 비 데몬 데몬 스레드와 스레드를 구별하는 것이 필요하다.

1. 데몬 스레드 및 비 데몬 스레드는 무엇입니까?

이 기본 시작 스레드는 그는 구체적으로 몇 가지 배경 작업 처리, 데몬 스레드입니다. 그래서 예를 들어, 쓰레기 수집 및하십시오. 이 비 데몬 스레드는 우리 자신의 창조의 스레드입니다. 공식 문서는 자바 가상 머신없는 비 데몬 스레드와 스레드가 디폴트를 종료 할 때, 상태. 예를 들어, 당신은 이해할 수있다 :

호텔 직원 내부 데몬 스레드와 마찬가지로, 고객과 같은 비 데몬 스레드, 고객은 더 수반 이상 필요가 아니다.

2, 코드를 보여줍니다

우리는 자신의 역할을 설명하기 위해 코드를 통해 볼

public class Test {
	public static void main(String[] args) {
		Thread thread = new Thread(()->{
			while (true) {
				System.out.println("无限循环");
			}
		}) ;
		thread.start();
	}
}
复制代码

여기에 두 가지 스레드가 메인 스레드가되어 있으며, 두 번째 스레드는 자신을 생성됩니다. 실행 한 후에는 스레드가 아닌 데몬 스레드 때문에 프로그램의 구현, 라디오에 갈 것이 분명하다. 실행도 메인 스레드는 스레드 실행의 마지막이 될 것입니다. 데몬 스레드가 동일하지 않은 것처럼 이제 우리는 스레드를 설정합니다.

public class Test {
	public static void main(String[] args) {
		Thread thread = new Thread(()->{
			while (true) {
				System.out.println("无限循环");
			}
		}) ;
		//设置为守护线程
		thread.setDaemon(true);
		thread.start();
	}
}
复制代码

다시 실행, 우리는 우리가 스레드가 데몬 스레드 된 설정 때문입니다, 정상적인 절차에서 그것을 발견 할 것이다, 당신은 지금 웨이터,없이 고객이되었다 메인 스레드와 스레드에 대해 생각, 그래서이 데몬 스레드 쇼핑 나는 주위를 배회 왼쪽했다.

3, 데몬 스레드 시나리오?

당신이 데몬 스레드의 특성을 이해 한 후, 당신은 JVM을 종료하는 것도 따라 일부 스레드를 철회하고 싶었다 때와 예기치 못한 일을 수행하기 위해이 원리를 사용하여, 당신은 그를 데몬 스레드로 설정 넣을 수 있습니다.

개념의 기본적인 이해 후 우리는 생성자 스레드 봐.

둘째, 스레드 생성자

1 생성자

스레드 스레드 생성자는 총 8가

여기에서 우리는 새로운 클래스 쓰레드 그룹과 접촉. 가 나타내는 의미하는 것은 스레드가 스레드 그룹에 속하는 것입니다. 스레드는 또한 실행 가능한 인터페이스를 선언 할 수 있습니다, 스레드 그룹이 속하는 지정할 수 있습니다 때 위에서 우리는 스레드의 예에서 볼 수 있습니다. 의이 thread 그룹 쓰레드 그룹을 분석해 보겠습니다.

두 사람 사이의 관계는 이러한 방식으로 표현 될 수있다 :

상기에서 스레드 그룹, 우리가 당신에게 코드를 보여 우리가 어디 스레드를 지정할 수있다.

public class Test {
	public static void main(String[] args) {
		//为当前线程设置线程组
		ThreadGroup group= new ThreadGroup("线程组");
		Thread thread = new Thread(group,"当前线程");
		thread.start();
		System.out.print(thread.getThreadGroup().getName());
	}
}
//输出:线程组
复制代码

이것은 기본적인 사용법이지만, 우리가 지정된 스레드 그룹 출력 스레드에 속하지 않는 경우 어떤 결과가 될 것인가? 테스트 :

public class Test {
	public static void main(String[] args) {
		ThreadGroup group= new ThreadGroup("线程组");
		ThreadGroup maingroup = Thread.currentThread().getThreadGroup();
		
		Thread thread1 = new Thread(group,"线程A");
		Thread thread2 = new Thread("线程B");
		System.out.println(thread1.getThreadGroup().getName());
		System.out.println(thread2.getThreadGroup().getName());
		System.out.println(maingroup.getName());
	}
}
//输出:线程组 main main
复制代码

위의 코드의 평균 maingroup 메인 스레드 그룹이이 스레드에게 우리가 만든 스레드 그룹, 기본 스레드 B 스레드 그룹을 지정합니다. 출력은 다음 그와 그의 아버지의 스레드 그룹이 동일 스레드 스레드 그룹을 지정하지 않을 경우 우리가 찾을 수 있음을 나타냅니다.

2, 스레드 인스턴스화

팔 개 생성자 스레드 이상을 감안할 때, 우리는 스레드를 인스턴스화하는 이들 8 개 생성자를 사용할 수 있지만, 바닥은 그것을 수행하는 방법인가? 그것은 그게의 예와 같은 일반적인 범주로 될 수 있을까? 이 점에서 우리는 깊은 소스 스레드를 볼 필요가 :

public Thread(ThreadGroup group, Runnable target, String name, long stackSize) {
    init(group, target, name, stackSize);
}
复制代码

우리는 다른 건축 방법의 일부이기 때문에, 가장 복잡한 시공 방법 중 하나를 선택, 우리가 진정으로 초기화 init 메소드에서 수행된다, 실제로 init 메소드를 호출 여기에서 볼 수 있습니다. 우리는뿐만 아니라 표정으로 갈 수 있습니다

private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
    init(g, target, name, stackSize, null, true);
}
复制代码

초기화 방법은 하나이지만 파라미터 중 두 개 이상 존재한다. 밖으로 우리가 가서보고 얘기를해야 찾으려면 :

    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        //第一部分:确保线程名字不为空
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
        this.name = name;
        //第二部分:指定线程组
        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            if (security != null) {
                g = security.getThreadGroup();
            }
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }
        g.checkAccess();
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }
        g.addUnstarted();
        this.group = g;
        //第三部分:一些其他参数设置
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        //第四部分:runnable接口配置
        this.target = target;
        setPriority(priority);
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        //第五部分:设置栈大小
        this.stackSize = stackSize;

        //第六部分:设置线程ID
        tid = nextThreadID();
    }

复制代码

마지막으로 우리는 스레드를 초기화 할 수있는 방법을 발견했다. 우리는 다섯 개 부분으로 나누어 :

(1) 부 : 스레드 이름은 비워 둘 수 없습니다,

개발자가 스레드의 이름을 지정하는 표시하지 않는 경우 여기에 하나의 스레드의 이름을 언급 할 것, 자바 관계자는 우리에게 물었다 스레드는 "스레드 -"는 thread의 이름으로 구성된 디지털 접미사 접두사가 될 것입니다. 그러나 어떤 경우에도 우리는 스레드 이름이 필요합니다.

(2) 파트 II : 현재 스레드의 스레드 그룹을 지정합니다

코드 내부 g가 비어 있지 않은 경우, 우리는 그렇지 않으면 스레드 그룹의 상위 클래스를 사용, 스레드 그룹 g 현재의 thread로 이것을 사용하고 있는지, 매우 분명하다. 물론, 중간에뿐만 아니라 등등 권한 문제 등을 확인한다.

(3) 제 III 부 : 기타 구성

다음은 구성이 너무 스레드, 우선 순위, 클래스 로더 및 데몬에 설정되어 있습니다.

(4) 제 IV : 실행 가능한 인터페이스 구성

지정은 실행 가능한 인터페이스 클래스를 구현합니다.

(5) 제 V는 : 스택의 크기를 설정합니다

스레드 스택의 크기는 인수 제로 전송 프로세스의 기본 크기 스레드 스택 즉 기본 크기에 따라 알 수있다

(6) 제 VI : 쓰레드 ID를 설정

스레드 ID가 nextThreadID 방법으로 특정된다. 우리는 스레드 ID를 지정하는 방법을 볼 수 있습니다.

private static synchronized long nextThreadID() {
    return ++threadSeqNumber;
}
复制代码

우리는 사실, threadSeqNumber을 볼 수 있습니다.

OK, 위의 나는 우리가 아주 명확하다 생각 스레드를 초기화하는 방법이며,이 생성자 초기화 방법의 다른 매개 변수는 단지 몇 가지 변경했습니다. 하지만 원리는 동일합니다. 이전 기사에서 언급 한 문제는 아직 읽어 해결되지 않았습니다.

라고 셋째, 왜 시작 방법은 스레드를 시작할 수 있습니다

이 문제를 해결하기 위해 우리는 또한 깊이 (jdk1.8)의 소스 코드를보고있다 :

   public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
复制代码

이 코드는 무엇을 의미합니까? 먼저 스레드 상태가 비정상 여부를 결정합니다, 현재 스레드가 스레드 마지막 호출을 시작하는 시작 start0 공식적인 방법 전에 스레드 그룹에 추가됩니다. 이제 열쇠는 여기에, 우리는뿐만 아니라 모양을 잡기에 갈 수도 start0 방법이 정말 시작 스레드입니다 :

즉, 시작하는 기본 방법의 진정한 시작이다, 실행 방법은 그것의 내용 안에 실행 왜 메서드 호출이 실행되지 것 같다. 공식 문서는 설명 그렇게되어 JNI 메소드가 내부 실행 start0 메소드를 호출합니다. 이러한 문장은 위의 이유를 설명하는 것입니다.

이미이 문제를 해결, 제 생성자이며, 우리가 시작 방법은 실행보다는 스레드를 시작할 수 있습니다 부르는 이유 두 번째는 이해합니다. 우리는 API 메소드가 실질적으로 모든 네이티브 스레드를 제공, 소스 코드를 알 수 분석 할 수 있습니다.

추천

출처juejin.im/post/5d5bb572f265da03bd051eb9