$start()$ 메소드는 스레드를 시작하는 데 사용됩니다. 이때 스레드는 ready(실행 가능) 상태이며 $cpu가 실행되지 않습니다. $ 시간 조각을 얻었습니다. $run()$ 메서드 실행을 시작합니다. $run()$ 메소드를 직접 호출하는 것은 본질적으로 현재 스레드에서 실행되는 클래스의 메소드만 호출하므로 $start()$ 메소드를 사용하여 $run()$를 호출해야만 달성할 수 있습니다. 방법. 진정한 멀티스레딩.
@Slf4j(topic = "c.Test4") public class Test4 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { log.debug("running"); } }; t1.run(); } }
위 코드는 직접 호출되는 $run()$ 메소드입니다. $main$ 스레드가 이 메서드를 실행했다는 인쇄된 정보를 볼 수 있습니다.
@Slf4j(topic = "c.Test4") public class Test4 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { log.debug("running"); } }; t1.start(); } }
그리고 $start()$ 메소드를 사용하여 시작하면 $t1$ 스레드에 의해 실행되는 실제 $run$ 메소드입니다.
$Thread$ 객체가 $start()$ 메서드를 호출하면 준비 상태로 들어가므로 $start()$ 메서드를 호출할 수 없습니다. 그렇지 않으면 다음 코드에 표시된 대로 $IllegalThreadStateException$ 예외가 발생합니다.
@Slf4j(topic = "c.Test4") public class Test4 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { log.debug("running"); } }; t1.start(); t1.start(); } }
예외 정보:
$sleep()$ 메서드를 호출하면 현재 스레드가 $Running$ 상태에서 $Time Waiting$ 상태로 변경됩니다(차단됨)
다른 스레드는 $interrupt$ 메서드를 사용하여 잠자는 스레드를 중단할 수 있습니다. 이때 $sleep$ 메서드는 throw InterruptedException
슬리핑 후 스레드가 즉시 실행되지 않을 수 있습니다
더 나은 가독성을 얻으려면 $Thread$의 $sleep$ 대신 $TimeUnit$의 $sleep$을 사용하는 것이 좋습니다. 샘플 코드
@Slf4j(topic = "c.Test5") public class Test5 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t1.start(); log.debug("t1 state {}", t1.getState()); //让主线程休眠500ms try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("t1 state {}", t1.getState()); } } //17:13:21.729 [main] DEBUG c.Test5 - t1 state RUNNABLE //17:13:22.245 [main] DEBUG c.Test5 - t1 state TIMED_WAITING
위 코드에서는 $t1$ 스레드가 먼저 시작되는데, 이때 인쇄 스레드의 상태는 $RUNNABLE$ 상태여야 하며, 메인 스레드를 sleep 상태로 두면 메인 스레드가 인쇄를 먼저 실행하지 못하게 됩니다. , 그러나 아직 $sleep()$ 상태에 들어가지 않았습니다. $run()$의 $sleep$ 메소드가 실행되면 스레드는 $TIMED WAITING$ 상태가 됩니다
@Slf4j(topic = "c.Test6") public class Thread6 { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread("t1") { @Override public void run() { try { log.debug("enter sleep"); Thread.sleep(2000); } catch (InterruptedException e) { log.debug("wake up"); e.printStackTrace(); } } }; t1.start(); Thread.sleep(1000); log.debug("interrupt t1"); //被唤醒 t1.interrupt(); } }
실행 결과
위 코드에서 $start$ 메소드가 시작되면, $t1$ 스레드는 슬립 상태에 들어가고 프롬프트 정보를 인쇄하며 슬립 시간은 $2s$입니다. $main$ 스레드에서 $1s$를 슬립한 후 $t1$ 스레드의 슬립을 중단하고 중단 메시지를 표시합니다. 정보를 확인하고 $interrupt()$ 메서드를 호출합니다. 이 시점에서 스레드가 중단되고 예외가 발생합니다.
$TimeUnit$ 클래스에는 더 읽기 쉬운 새로운 단위가 추가되었지만 본질적으로 차이는 없습니다. 이는 단지 단위 변환일 뿐입니다
TimeUnit.SECONDS.sleep(1);//该语句作用是睡眠一秒
$yield$를 호출하면 현재 프로세스 $Running$에서 $Runnable$ 준비 상태로 들어간 후 다른 스레드를 예약하고 실행합니다. 구체적인 구현은 운영 체제의 작업 스케줄러에 따라 다릅니다(즉, 작업 스케줄러에 다른 작업이 없는 경우에도 마찬가지입니다. $cpu$를 포기하면 스레드를 계속 실행합니다.) $sleep$은 실행 후 차단 상태로 들어갑니다. 이때 sleep 시간이 끝나지 않으면 $cpu$는 스레드에 할당되지 않습니다. $yield$는 준비 상태로 들어갑니다. 즉, 다른 스레드를 실행할 필요가 없으면 스레드에도 시간 조각이 할당됩니다. 이는 $sleep$과 $yield$ 스레드 우선순위
는 스케줄러에게 스레드 예약의 우선 순위를 지정하라는 메시지를 표시하지만 이는 단지 메시지일 뿐이므로 스케줄러는 무시할 수 있습니다.
$cpu$가 사용 중인 경우 우선 순위가 더 높은 항목이 더 많은 시간 조각을 얻지만 $cpu $가 유휴 상태이면 우선 순위가 거의 존재하지 않습니다
without $cpu$를 사용하여 계산할 때 $while(true)$를 유휴 상태로 두지 말고 $cpu를 낭비하세요. $. 이때 $yield$ 또는 $sleep$을 사용하여 $cpu$ 사용을 다른 프로그램에 넘길 수 있습니다
while (true) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } }
예 $wait$ 또는 조건 변수를 사용하면 유사한 효과를 얻을 수 있습니다
차이점은 후자입니다. 두 개는 잠금 및 해당 깨우기 작업이 필요하며 일반적으로 동기화가 필요한 시나리오에 적합합니다
$sleep$는 잠금 동기화가 필요하지 않은 시나리오에 적합합니다
다음 프로그램의 인쇄 결과:
@Slf4j(topic = "c.Test6") public class Test6 { static int r = 0; public static void main(String[] args) { test(); } private static void test() { log.debug("开始"); Thread t = new Thread("t1") { @Override public void run() { log.debug("开始"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("结束"); r = 10; } }; t.start(); log.debug("r的值是{}", r); log.debug("结束"); } }
메인 스레드와 $t1$ 스레드가 병렬이므로 $t1$ 스레드는 $r$ 값을 계산하려면 $1s$가 필요하며, 메인 스레드는 $r$ 값을 다음과 같이 인쇄합니다. 시작이므로 인쇄된 값은 0
입니다. 해결 방법:
Can인 $t.start();$ 뒤에 $t.join();$을 추가합니다. $join$의 기능은 스레드 실행이 완료될 때까지 기다리는 것입니다.
호출자 입장에서 실행을 계속하기 전에 결과가 반환될 때까지 기다려야 한다면 동기식이고, 실행을 계속하기 위해 반환 결과를 기다릴 필요가 없다면 비동기식입니다.
그래서 $join$ 메소드는 실제로 동기식으로 실행되도록 허용합니다.
$join(milliseconds)$ 메소드는 스레드 실행 시간이 짧은 경우 대기 시간에 전달할 매개변수를 가질 수 있습니다. 대기 시간보다 크면 대기 시간이 지나면 대기가 중지됩니다. 스레드 실행 시간이 대기 시간보다 작으면 스레드 실행이 완료된 후 대기가 종료됩니다. 설정된 대기 시간은 만료되지 않습니다.
打断$sleep, wait, join$的线程,即打断阻塞状态的线程
打断$sleep$的线程,会清空打断状态
@Slf4j(topic = "c.Test7") public class Test7 { public static void main(String[] args) throws InterruptedException { Thread t = new Thread("t1"){ @Override public void run() { log.debug("sleep..."); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t.start(); Thread.sleep(1000); log.debug("interrupt"); t.interrupt(); log.debug("打断标记: {}", t.isInterrupted()); } }
因此我们可以在线程中判断打断标记,来决定是否被打断,以及执行被打断之前的收尾工作。
@Slf4j(topic = "c.Test8") public class Test8 { public static void main(String[] args) throws InterruptedException { Thread t = new Thread("t1"){ @Override public void run() { while (true) { if (Thread.currentThread().isInterrupted()) { log.debug("线程被打断了"); break; } } } }; t.start(); Thread.sleep(1000); log.debug("interrupt"); t.interrupt(); } }
默认情况下,$java$需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程,只要其他非守护线程运行结束了,即使守护线程的代码没有执行完毕,也会强制结束。
@Slf4j(topic = "c.Test10") public class Test10 { public static void main(String[] args) throws InterruptedException { Thread t = new Thread("t1") { @Override public void run() { while (true) { } } }; //设置线程为守护线程 t.setDaemon(true); t.start(); Thread.sleep(1000); log.debug("主线程结束"); } }
如果不把$t$设置为守护线程,则因为线程内部的死循环,导致程序不会结束运行。
위 내용은 Java 스레드에서 시작 메소드와 실행 메소드를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!