做外贸的要有自己的网站吗,php编程,wordpress 比较好的插件,张家港建网站公司线程
线程的常见属性
线程属性可以通过下面的表格查看。 •ID 是线程的唯⼀标识#xff0c;不同线程不会重复 • 名称是各种调试⼯具⽤到#xff08;如jconsoloe#xff09; • 状态表示线程当前所处的⼀个情况#xff0c;下⾯我们会进⼀步说明 • 优先级高的线程理论上来…线程
线程的常见属性
线程属性可以通过下面的表格查看。 •ID 是线程的唯⼀标识不同线程不会重复 • 名称是各种调试⼯具⽤到如jconsoloe • 状态表示线程当前所处的⼀个情况下⾯我们会进⼀步说明 • 优先级高的线程理论上来说更容易被调度到 • 关于后台线程需要记住⼀点JVM会在⼀个进程的所有非后台线程结束后才会结束运⾏。 • 是否存活即简单的理解为 run 方法是否运⾏结束 • 线程的中断问题下⾯我们进⼀步说明
线程的状态
线程状态分为New、Terminated、Runnable、Waiting、Timed_Waiting、Blocked观测线程状态可以通过jconsole观察。
New 该状态下存在Thread对象还没有调用start系统内部PCB还未创建Terminated 该状态下表示线程已终止内部创建的PCB已经销毁Thread对象还在Runnable 该状态下表示线程正在CPU上执行随时可以被调度。Waiting 死等状态进入的阻塞Timed_Waiting 带有规定时间的等待Blocked 进行锁竞争后出现的阻塞状态
线程状态之间的转换图省略版
线程是否存活
在线程生命周期中根据观察线程中的PCB是否存在。
Thread t new Thread(()-{});在这段代码中线程t只是初始化了一个Thread对象但是其中的PCB只有在执行了t.start()以后才会被创建出来。
public static void main(String[] args) {Thread t new Thread(()-{});t.start();try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}在上面的代码中线程t在启动以后创建了PCB但是因为t中代码块没有任何代码所以线程t很快就运行结束了内核中的线程和PCB马上就被销毁了。而在main线程中通过sleep停止了2s因此线程t的PCB被销毁而t这个对象并没有被gc回收t仍然是存在的。 在下面的代码中我加上了tnull通过这个方法以求解决t对象能够被gc回收。但显然是不行的通过tnull可能会导致t线程还没结束t对象就为空了。
public static void main(String[] args) {Thread t new Thread(()-{});t.start();t null;try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}因此Thread给了我们一种属性isAlive是否存活。通过这个属性我们可以查看到线程是否存在并对线程t进行操作。
public static void main(String[] args) throws InterruptedException {Thread t new Thread(()-{for (int i 0; i 5; i) {System.out.println(hello );}System.out.println(线程t是否存活Thread.currentThread().isAlive());});t.start();Thread.sleep(3000);System.out.println(线程t是否存活 t.isAlive());}结果如下图
前台线程和后台线程的关系与区别
线程是并发执行的。当然当线程多了以后为了能够不让某些线程影响整个进程的结束更好的利用系统资源。于是为线程设计了前台和后台两个线程方式。在前台线程中如果本线程运行没有结束则此时Java进程也无法结束。在后台线程中即使该线程还处于执行阶段当前台线程都结束以后意味着整个Java进程即将结束。那么这时候后台线程就不得不停止执行了。 简单来说前台线程决定了Java进程的时间后台线程无法控制整个进程的时间只能被迫跟着前台线程的结束而结束。 前台线程也可以是多个的只有最后一个前台线程结束整个Java进程才结束。
设置线程的前后台
在Java中main线程以及默认情况下的线程都属于前台线程。而改变线程前后台的方式可以通过修改线程前后台属性 t.setDaemon(true) 将对应线程转变为后台线程。
接下来使用一个例子进行简单演示public class Demo1 {public static void main(String[] args) {Thread t new Thread(() - {while (true) {for (int i 0;i5;i) {System.out.println(hello thread);}}});t.setDaemon(true);t.start();for (int i 0; i 5; i) {System.out.println(hello main);}}
}在上面的代码中我们可以看到理论上来说线程t应当是进入死循环不断打印hello thread的但是我在线程启动之前将t线程设置为后台线程。因此在main线程运行结束以后垃圾回收机制gc将main线程回收前台线程结束后台线程t自然也只能被迫结束。
线程核心操作
启动 t.start()
通过多次的练习已经明白t.start()执行后创建线程PCB真正创建线程并开始执行。不再过多赘述
终止 interrupt()
在Java中终止线程不是简单的停止线程的执行。而是对线程进行提醒提醒线程是否停止而真正做决定的还是该线程本身。 1通过变量控制终止线程 private static boolean isRunningtrue;public static void main(String[] args) throws InterruptedException {// boolean isRunning true;//变量捕获Thread t2 new Thread(()-{while (isRunning) {System.out.println(hello thread);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(t2线程被结束了);});t2.start();Thread.sleep(4000);System.out.println(控制t2线程结束);isRunning false;}结果如下图 2使用线程的interrupt和isInterrupted方法 通过下面的代码进行解释在这个代码块中线程t3通过isInterrupted判断是否结束这个循环而在main线程中通过t.interrupt方法将这个值修改为false,抛出RuntimeException异常结束了当前的线程。
public static void main(String[] args) throws InterruptedException {Thread t3 new Thread(()-{while (!Thread.currentThread().isInterrupted()) {System.out.println(hello Thread);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException();//抛出异常并结束}}System.out.println(t2线程被结束了);});t3.start();Thread.sleep(3000);t3.interrupt();}3提醒线程而不终止 在下面的代码中修改了boolean之后线程t3并没有停止线程而是打印出异常信息之后继续执行。 在这里出现了一个问题为什么通过interrupt方法之后修改了boolean值但是在线程抛出异常之后仍然在继续打印呢 首先interrupt方法修改了boolean值的标志位修改为true在slee过程中通过interrupt方法强制唤醒线程在强制唤醒后清除了刚刚的标志位重新修正回flase。
public static void main(String[] args) throws InterruptedException {Thread t3 new Thread(()-{while (!Thread.currentThread().isInterrupted()) {System.out.println(hello Thread);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace(); //打印异常信息而不结束//throw new RuntimeException();//抛出异常并结束}}System.out.println(t2线程被结束了);});t3.start();Thread.sleep(3000);t3.interrupt();}等待join()
因为线程是抢占式执行的其调度顺序在系统中是无序的。而这种无序的执行方式不在程序猿的掌控之中因此我们希望能够通过一些方式控制这些线程。join等待就是其中一种方式。
基本用法 在下面的代码块中分为main线程和t两个线程。我们可以注意到与之前的写法其实是大差不差的唯一区别的是在try-catch包裹下出现的t.join()方法。 在main线程中使用t.join的作用让main线程进入阻塞等待状态t线程执行完之后main线程才会接着往下执行。 通过这样的方式在一定程度上解决了线程的控制问题。
public static void main(String[] args) {Thread t new Thread(() - {for (int i 0; i 5; i) {System.out.println(hello thread);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(thread end);});t.start();try {t.join();} catch (InterruptedException e) {throw new RuntimeException(e);}for (int i 0; i 5; i) {System.out.println(hello main);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(main end);}因此我们可以看到结果如下图所示
多个线程的join 在多个线程等待代码了解之前我们必须了解的是在main线程中调用t1.join是main线程等待t1而与其他线程无关main线程是不会等待其他线程的。当多线程的情况下也是这般理解的。 在下面的代码中存在t1和t2两个线程在main线程中同时调用t1.join()和t2.join() 这意味着main线程只有等t1线程和t2线程全部执行完毕以后才会往下执行。t1和t2线程各自调度执行互不影响。 所需的时间是t1线程和t2线程运行时间较长的。
public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() - {for (int i 0; i 10; i) {System.out.println(hello thread);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(t1 end);});Thread t2 new Thread(() - {for (int i 0; i 10; i) {System.out.println(hello thread);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(t2 end);});t1.start();t2.start();t1.join();t2.join();for (int i 0; i 10; i) {System.out.println(hello main);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(main end);}有限时间内等待 在上面两个情况下对于t.join()的方法只有等待线程t运行结束以后才能进行下一步属于死等状态。那么如果出现意料之外的情况线程t无法结束那么整个程序都会因此卡住无法执行后续的逻辑极大降低了系统的容错。 因此Java提供了join带参数的两种方法。通过这两种方法当线程超过规定时间而不结束则主线程不再等待继续执行下面的逻辑。 接下来简单写个demo 在这个demo中存在三个线程分别为t1、t2、main。在代码中我通过t1.join()让两个线程都进行阻塞状态等待线程t1结束。而对于t2不相同的是我只让main线程等待2s超过两秒之后main线程不再是阻塞状态而是执行下面的逻辑。
public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() - {for (int i 0; i 5; i) {System.out.println(hello t1);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(t1 end);});Thread t2 new Thread(() - {try {t1.join();} catch (InterruptedException e) {throw new RuntimeException(e);}for (int i 0; i 5; i) {System.out.println(hello t2);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(t2 end);});t1.start();t2.start();t1.join();t2.join(2000);//等待2s后main线程自己走了for (int i 0; i 5; i) {System.out.println(hello main);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(main end);}因此代码结果如下
总结
多线程有许多常见属性以及各类用法都是需要熟练掌握的。 源码多线程相关代码