欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java线程的控制详解

程序员文章站 2024-02-29 19:41:16
1. join线程: 在线程执行过程中,有时想让另一个线程先执行,比如将一大问题分割成许多小问题,给每一个小问题分配线程,但所有小问题处理完后再让主线程进一步操作。此时我...

1. join线程

在线程执行过程中,有时想让另一个线程先执行,比如将一大问题分割成许多小问题,给每一个小问题分配线程,但所有小问题处理完后再让主线程进一步操作。此时我们可以在主线程中调用其它线程的join()方法,以阻塞调用线程(在这里为主线程)。

示例代码:

复制代码 代码如下:

 package org.frzh.thread;
 
 public class jointhread extends thread{
     //提供一个有参构造器,用来设置线程的名字
     public jointhread(string name) {
         super(name);
     }
    
     public void run() {
         for (int i = 0; i < 100; i++) {
             system.out.println(getname() + " " + i);
         }
     }
    
     public static void main(string[] args) {
         //启动子线程
         new jointhread("新线程").start();
         for (int i = 0; i < 100; i++) {
             if (i == 20) {
                 jointhread jt = new jointhread("被join的线程");
                 jt.start();
                 //main线程调用了jt线程的join方法,则main线程必须等待jt执行完之后才能执行
                 try {
                     jt.join();
                 } catch (interruptedexception e) {
                     // todo auto-generated catch block
                     e.printstacktrace();
                 }
             }
             system.out.println(thread.currentthread().getname() + " " +i);
         }
     }
 }

本来有三套线程(两条子线程和一main线程),当i=20后,main线程被阻塞必须等到“被join线程”执行完之后才有机会执行,所以此后只有两条线程执行。

join()方法的三种重载形式:

join():等待被join线程执行完;

join(long millis):等待被join线程执行最长为mills豪秒,在这之后即使被join线程没有执行完也不再等待;

join(long millis, int nanos):等待被join线程执行最长时间为millis毫秒+nanos微秒。(此方法基本用不上)。

2:后台线程

有一种线程,他是在后台运行,他的任务是为其他线程服务,这种线程被称为“后台线程”、“守护线程”或“精灵线程”。当所有前台线程都死亡后,后台线程会自动死亡。

示例代码:

复制代码 代码如下:

 package org.frzh.thread;
 
 public class daemonthread extends thread{
     public void run() {
         for (int i = 0; i < 1000; i++) {
             system.out.println(getname() + " " +i);
         }
     }
    
     public static void main(string[] args) {
         daemonthread dt = new daemonthread();
         //将此线程设置为后台线程
         dt.setdaemon(true);
         dt.start();
         for (int i = 0; i < 10; i++) {
             system.out.println(thread.currentthread().getname() + " " + i);
         }
         //前台线程结束,那么后台线程dt也会结束,所以它执行不到999
     }
 }

主线程默认是前台线程,前台线程创建的子线程默认是前台线程,后台线程创建的子线程默认是后台线程。

3.线程睡眠(sleep):

前面的join方法是让调用线程等待被join线程执行完之后再继续执行,而sleep()方法是让调用线程阻塞一段时间后再重新进入就绪状态等待被调度。因此它通常用来暂停程序的执行。

示例代码:

复制代码 代码如下:

 package org.frzh.thread;
 
 import java.util.date;
 
 public class sleepthread{
     public static void main(string[] args) {
         for (int i = 0; i < 10; i++) {
             system.out.println("当前时间:" + new date());
             try {
                 thread.sleep(1000);
             } catch (interruptedexception e) {
                 // todo auto-generated catch block
                 e.printstacktrace();
             }
         }
     }
 }

sleep()方法的两种重载方式:

static void sleep(long millis):让当前线程暂停millis毫秒,并进入阻塞状态。该方法会受到系统计时器和线程调度器的精度和准度的影响。

static void sleep(long millis, int nanos):暂停mills毫秒+nanos微秒,并进入阻塞状态,同样会受系统计时器和线程调度器的精度和准度的影响。基本不用。

4.线程让步(yield):

yield()方法和sleep方法有点类似,它同样可以使当前正在运行的线程暂停,但他不会阻塞该线程,只是将他转入就绪状态(注意不是阻塞状态)。yield()方法只会让和它同等优先级或更高优先级的线程有被执行的机会,所以某一线程调用该方法后可能又被重新调度回来继续执行。

示例代码:

复制代码 代码如下:

 package org.frzh.thread;
 
 public class yieldthread extends thread{
     public yieldthread() {
        
     }
     public yieldthread(string name) {
         super(name);
     }
     public void run() {
         for (int i = 0; i < 100; i++) {
             system.out.println(getname() + " " +i);
             if (i == 20) {
                 //当前线程让步
                 thread.yield();
             }
         }
        
     }
    
     public static void main(string[] args) {
         //启动两条并发线程
         yieldthread yt1 = new yieldthread("高级");
         //设置yt1为最高优先级
         yt1.setpriority(thread.max_priority);
         yt1.start();
         yieldthread yt2 = new yieldthread("低级");
         yt2.setpriority(thread.min_priority);
         yt2.start();
         /*
          * 如果不给线程设置优先级,则两个线程的优先级是相同的,所以两线程会交替执行,当调用yield后会让另一个线程执行;
          * 但是,给两个线程分别设置上述优先级之后,刚开始高级线程执行,当i=20时,调用yield,但由于yield方法只会
          * 给和它同优先级或更高优先级的线程执行机会,所以此时仍是高级线程执行,而不会让给低级线程
          */
     }
 }

5:改变线程的优先级

此举比较简单,只需调用调用实例方法setpriority(int priority)方法即可。每个线程默认与其父线程的优先级相同,main线程默认具有普通优先级(5)。java提供1~10个优先级,也可以使用三个静态常量:

max_priority:10

min_priority:1

norm_priority:5

注意的是:尽管java提供10个优先级,但是不同的系统支持的优先级不一样,所以尽量避免直接使用1~10之间的数字,而使用静态常量,以保证具有良好的可移植性。