多线程:控制线程

来源:互联网 发布:公安大数据分析研判 编辑:程序博客网 时间:2024/05/22 15:45

一、后台线程(守护线程)

守护线程,是指在程序运行的时候在后台提供一种通用服务的线程,比如JVM垃圾回收线程就是一个典型的守护线程,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非守护线程结束时,程序就没运行的必要了,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。

调用Thread对象的setDaemon(true)方法可以将该线程设置成后台线程。该方法必须在启动线程前调用。 

还有一个方法isDaemon()方法可以测试该线程是否为守护线程。

public class DaemonThread extends Thread {public static void main(String[] args) {DaemonThread thread = new DaemonThread();// 将此线程设置成后台线程thread.setDaemon(true);thread.start();for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + i);}}@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + i);}}}

运行结果:

...Thread-0 10main 9Thread-0 11...Thread-0 32Thread-0 33...

可以看到当主线程运行完后,守护线程无法运行到循环变量100,可以判断出当非守护线程全部结束时,守护线程也会结束。

二、线程睡眠

通过调用Thread类的静态方法sleep(),可以在指定的毫秒数内让当前正在执行的线程阻塞(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。该线程不丢失任何监视器的所属权。

public class SleepTest {public static void main(String[] args) throws Exception {for(int i =0;i<10;i++) {System.out.println("当前时间:"+new java.util.Date());Thread.sleep(1000);}}}

运行结果:

当前时间:Fri Sep 29 15:00:16 CST 2017当前时间:Fri Sep 29 15:00:17 CST 2017当前时间:Fri Sep 29 15:00:18 CST 2017

运行上面程序可以看到程序输出一次当前时间后,程序暂停一秒,然后再输出一次。

三、join线程

当在某个线程中调用其他线程的join()方法时,调用的线程会被阻塞,直到join线程执行完为止。

public class JoinThread extends Thread {public JoinThread(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 2; i++) {System.out.println(getName() + " " + i);}}public static void main(String[] args) throws Exception {for (int i = 0; i < 10; i++) {if (i == 3) {JoinThread jt = new JoinThread("执行join的线程");jt.start();jt.join();}System.out.println(Thread.currentThread().getName() + " " + i);}}}

运行结果:

main 0main 1main 2执行join的线程 0执行join的线程 1main 3...

可以看到调用join()方法的主线程被阻塞,知道join线程执行完才开始执行下面的代码。

四、线程的优先级

每个线程执行时都具有一定的优先级,优先级高的线程会获得更多的执行机会,而优先级低的则较少。

每个线程默认的优先级与创建它的父线程的优先级相同,在默认情况下,main线程具有普通优先级(NORM_PRIORITY)。

Thread类提供了setPriority(int newPriority)、getPriority()方法来设置和返回指定线程的优先级,其中setPriority()方法的参数是一个整数,范围是1~10,也可以是下面的镜头常量。

Thread类有如下三个静态常量:

  • NORM_PRIORITY:其值是5
  • MIN_PRIORITY:其值是1
  • MAX_PRIORITY:其值是10
public class PriorityTest extends Thread {public PriorityTest(String name) {super(name);}public void run() {for (int i = 0; i < 10; i++) {System.out.println(getName() + ",其优先级是:" + getPriority() + ",循环变量的值为:" + i);}}public static void main(String[] args) {System.out.println("主线程的优先级:" + Thread.currentThread().getPriority());PriorityTest low = new PriorityTest("低优先级线程");PriorityTest high = new PriorityTest("高优先级线程");System.out.println(low.getName()+"创建之前的的优先级:"+low.getPriority());System.out.println(high.getName()+"创建之前的的优先级:"+high.getPriority());low.start();low.setPriority(MIN_PRIORITY);high.start();high.setPriority(MAX_PRIORITY);}}

运行几次看到的结果都是high线程优先执行完的。

五、线程让步

yield()方法与sleep()方法相似,同样是Thread类的静态方法,也可以让当前线程暂停,但它不会阻塞该线程,而是将该线程转入就绪状态。yield()只是让当前线程暂停一下,让系统重新调度一次,所以很有可能重新执行原来的线程,而且该方法受优先级影响。

public class YieldTest extends Thread {@Overridepublic void run() {for(int i=0;i<20;i++) {System.out.println(getName() + " " + i);if(i==5) {Thread.yield();}}}public static void main(String[] args) {YieldTest yt1 = new YieldTest();YieldTest yt2 = new YieldTest();yt1.start();yt2.start();}}

运行结果:

...Thread-1 4Thread-0 5Thread-1 5Thread-0 6...

程序开启两条优先级一样的线程,两个线程的循环变量i执行到5的时候,会发现线程会切换给另一个线程执行。