公司网站实名认证,展示设计网站有哪些,做网站的多少钱,网站如何做sem推广【线程】Java线程操作 一、启动线程1.1 run()和start()的区别 二、终止线程三、等待线程四、线程的状态 一、启动线程
Java中通过start()方法来启动一个线程#xff0c;其次我们要着重理解start()和run()的区别。
1.1 run()和start()的区别
我们通过一份代码来进行观察其次我们要着重理解start()和run()的区别。
1.1 run()和start()的区别
我们通过一份代码来进行观察
public class ThreadDemo1 {public static void main(String[] args) throws InterruptedException {Thread tnew Thread(()- {while(true){System.out.println(hello 000);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//第一次运行start()t.start();//第二次运行run()//t.run()while (true){System.out.println(hello 111);Thread.sleep(1000);}}
}从结果上来看用start() 方法两个线程都正常运行了main线程和t线程而使用run()方法似乎只有一个线程在正常运行。 我们可以用Jconsole来查看一下 可以发现使用start()方法真正创建出了线程而使用run()方法只是在main线程里执行t线程对象的逻辑并没有真正创建线程。那么我们可以这样理解** start()方法用于创建线程系统在合适的时机调用run方法run()方法用于执行线程内部的逻辑。**
二、终止线程
想要终止一个线程其实是需要里外配合的。具体来说比如我们想要在main线程内控制t线程我们就需要在t线程中引入一个标志位用来控制线程。同时我们要能在main线程中能够控制这个标志位。接下来看示例
手动设置标志位
public class ThreadDemo1 {private static boolean isQuit false;public static void main(String[] args) throws InterruptedException {Thread tnew Thread(()- {while(!isQuit){System.out.println(hello);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();//这个时间需要大于t线程中的休眠时间//避免因线程的随机调度使得t线程还没启动标志位就被更改Thread.sleep(2000);isQuittrue;}
}运行结果 这里还有一个小问题 如果我们把isQuit自定义的标志位写到main方法内部作为一个局部变量此时就会编译报错。 这是因为λ表达式在进行变量捕获时对于外部定义的局部变量要求是final或者是effectively final类型的。 那为什么写成成员变量就可以了呢此时是走了另一条语法规则λ表达式/内部类可以访问外部类的成员变量这件事情不受λ表达式变量捕获的限制。
但是我们认为这种手动设置标志位的方式不够优雅Thread类呢提供了一种更加优雅的方法interrupt()。
使用Thread类提供的interrupt方法
public class ThreadDemo1 {public static void main(String[] args) throws InterruptedException {Thread tnew Thread(()- {while(!Thread.currentThread().isInterrupted()){System.out.println(hello);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();//这个时间需要大于t线程中的休眠时间//避免因线程的随机调度使得t线程还没启动标志位就被更改Thread.sleep(2000);t.interrupt();}
}Thread.currentThread()用于获取当前线程的引用如果是继承Thread那么可以用this引用但如果是实现Runnable或者是lambda表达式就只能使用该方法来获取当前线程的引用。 此处出现了一个比较奇怪的错误 : 明明已经报错了怎么还没停下来。 这里其实是sleep搞的鬼。 此处线程处于这种休眠状态调用interrupt()就会提前唤醒这个线程。线程被提前唤醒会做两件事 1抛出 InterruptedException异常被catch捕获到 2清除Thread对象的标志位把标志位继续设为false。 所以此时线程没有真正停止。而想要使这个线程停止只需要做出一点小小的改进在catch中写入break
try {Thread.sleep(1000);
} catch (InterruptedException e) {break;
}此时思考一个问题那么我手动设置标志位为什么不会有这样的问题 这是因为手动设置的标志位并不是Thread对象的属性只是当前类的一个成员变量。即使线程被提前唤醒也是不能去改变这里手动设置的标志位的。 Java这里对于线程的终止采用的是一种“软性”操作即需要线程配合才能终止。操作系统的API提供了强行终止线程的操作但这件事往往弊大于利Java中并没有引入这样的强制性方法。
三、等待线程
由于多个线程的执行顺序是不确定的随机调度抢占式执行所以我们的有些目的就难以实现。但是我们可以通过某些api来影响线程的执行顺序比如可以让一个线程来等待另一个线程。
public class ThreadDemo1 {public static void main(String[] args) throws InterruptedException {Thread tnew Thread(()- {for(int i0;i10;i){System.out.println(hello);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException();}}});t.start();t.join();System.out.println(这是主线程期望在t线程结束后打印);}
}这里的语法是这样在main线程中写入t.join()就是让main线程等待t线程执行完毕再继续执行。 从系统调度的角度来说这里就是让main线程主动放弃被系统调度的机会直到 t 线程执行完再恢复。 明确来讲这里不是确定的“执行顺序”而是确定的“结束顺序”。 join方法也可以设置一个时间避免要等的线程内部设计出了死循环而出现的“死等”。较为常用的就是这种join(long millis)。
四、线程的状态
之前谈到进程有就绪和阻塞两种状态。使用Jconsole也可以观察到线程的状态 Java中对线程的状态进行了进一步的细分
状态对应的含义NEWThread对象创建好了但是还没有调用start方法在系统中创建线程。TERMINATEDThread对象仍然存在但是系统内部的线程已经执行完了RUNNABLE就绪状态表示这个线程正在CPU上执行或者随时准备去CPU上执行TIMED_WAITING指定时间的阻塞到达一定时间后自动解除阻塞。例如sleep()、join(long millis)WAITING不带时间的阻塞死等必须满足一定的条件才解除阻塞BLOCKED由于锁竞争引起的阻塞 讲到这里大部分的状态我们都见识过了。对于BLOCKED的状态涉及到我们所要讲的线程安全问题后面在详细论述。