线程与多线程(四)——线程调度

四、线程调度

  线程调度管理器负责线程排队和CPU在线程间的分配,并按线程调度算法进行调度。当线程调度管理器选中某个线程时,该线程获得 CPU资源进人运行状态。
  线程调度是抢占式调度,即如果在当前线程执行过程中个更高优先级的线程进人可运行状态,则这个更高优先级的线程立即被调度执行。

3.1实现线程调度的方法
1. join( )方法
  join( )方法使当前线程暂停执行,等待调用该方法的线程结束后再继续执行本线程。它被重载了3次:

public final void join() 
public final void join(long mills)
public final void join(long mills,int nanos)

下面通过示例具体看一下join( )方法的应用。
示例1
  使用join( )方法阻塞线程。
  实现步骤:
  (1)定义线程类,输出5次当前线程的名称。
  (2)定义测试类,使用join()方法阻塞主线程。

// 线程类
public class MyThread extends Thread(
    public MyThread(string name){
        super(name);
    }
    public void run(){
    for(int i=0;i<5;i++){
        //输出当前线程的名称
        System.out.println(Thread.currentThread().getName() + "-" + i);
    } 
}
// 测试类
public class Test{
    /*
    * Java 程序中的public static void main( )方法是主线程的入口,
    * 运行Java程序时,会先执行这个方法。
    */
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            if (i == 5) {
                System.out.println("i:" + i);
                // 主线程运行5次后,开始myThread的线程
                MyThread myThread = new MyThread("myThread");
                try {
                    myThread.start();
                    // join()方法使当前线程暂停执行,等待调用该方法的线程结束后再继续执行本线程
                    // 把该线程通过join()方法插入到主线程前面,否则主线程执行完毕后再执行该线程
                    myThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // main,主线程
            System.out.println(Thread.currentThread().getName() + "-" + i);
        }
    }
}
// 再解释一遍流程。
// 1、主线程开始运行。
// 2、i等于5的时候,主线程暂停。
// 3、等待调用该方法的线程myThread执行完毕后继续执行主线程main。
main-0
main-1
main-2
main-3
main-4
i:5
myThread-0
myThread-1
myThread-2
myThread-3
myThread-4
main-5
main-6
main-7
main-8
main-9

  在示例1中,使用join( )方法阻塞指定的线程等到另一个线程完成以后再继续执行。其中myThread.join( )表示让当前线程即主线程main加到myThread的末尾,主线程被阻塞,myThread执行完以后主线程才能继续执行。
  Thread.curentThread().geName( )获取了当前线程的名称。
  从线程返回数据时也经常使用到join()方法。

示例2
  使用join( )方法实现两个线程间的数据传递。
  实现步骤:
  (1)定义线程类,为变量赋值。
  (2)定义测试类。

public class MyThread extends Thread{
    public String valuel;
    public String value2;   
    public void run() {
        valuel = "value1已赋值";
        value2 = "value2已赋值";
    }
}
public class Test {
    public static void main(Stringl[] args) throws InterruptedException{
        MyThread thread = new MyThread();
        thread.start();
        System.out.println("value1 :"+thread.value1);
        System.out.printin("value2 :"+thread.value2);
    }
}
// 输出结果:
valuel: null
value2: null

  在示例2中,在run( )方法中已经对value1和value2赋值,而返回的却是null,发生这种情况的原因是在主线程中调用start( )方法后就立刻输出了value1和value2的值,而这里run( )方法可能还没有执行到为valuel 和value2赋值的语句。要避免这种情况的发生,需要等run( )方法执行完后才执行输出value1和value2的代码,可以使用join( )方法来解决这个问题。修改示例2的代码,在“thread.start( );”后添加”thread.join();”,修改后此处代码如下:

public class Test {
    public static void main(Stringl[] args) throws InterruptedException{
        MyThread thread = new MyThread();
        thread.start();
        // join()方法
        thread.join();
        System.out.println("value1 :"+thread.value1);
        System.out.printin("value2 :"+thread.value2);
    }
}
// 重新运行示例2,则可以得到如下输出结果:
valuel: value1 己赋值
value2: value2 已赋值

—————————— 我是手动分割线 ——————————

2.sleep( )方法
  sleep( )方法定义语法如下:
  public static void sleep(long millis)
  sleep( )方法会让当 前线程睡眠(停止执行) millis毫秒,线程由运行中的状态进人不可运行状态,
睡眠时间过后线程会再进人可运行状态。
示例1
  使用sleep( )方法阻塞线程。
  实现步骤:
  (1)定义线程。
  (2)在run( )方法中使用sleep( )方法阻塞线程。
  (3)定义测试类。

public class SleepThreadTest {
    public static void bySec(long s) {
        for (int i = 0; i < s; i++) {
            try {
                // 睡眠1000毫秒
                Thread.sleep(1000);
                System.out.println("线程---"+Thread.currentThread().getName()+" 等待---"+ (i + 1) + "秒");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        System.out.println("please wait...");
        // 让主(该)线程等等5秒再执行
        SleepThreadTest.bySec(5);
        System.out.println("start...");
    }
}
// 运行结果
please wait...
线程---main 等待---1秒
线程---main 等待---2秒
线程---main 等待---3秒
线程---main 等待---4秒
线程---main 等待---5秒
start...

  示例3的代码中,在执行主线程以后,首先输出了please wait,然后主线程等待5秒后继续执行。

—————————— 我是手动分割线 ——————————

3.yield( )方法
  yield( )方法定义语法如下:
  public static void yield()
  yield( )方法可暂停当前线程执行,允许其他线程执行, 该线程仍处于可运行状态,不转为阻塞状态。此时,系统选择其他相同或更高优先级线程执行,若无其他相同或更高优先级线程,则该线程继续执行。
示例1
  使用yield()方法暂停线程。
  实现步骤:
  (1)定义两个线程。
  (2)在run( )方法中使用yield( )方法暂停线程。
  (3)定义测试类。

// 线程类1
public class FirstThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("第一个线程的第" + (i + 1) + "次运行" + Thread.currentThread().getName());
            // 暂停线程
            Thread.yield();
        }
    }
}
// 线程类2
public class SecThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("第二个线程的第" + (i + 1) + "次运行" + Thread.currentThread().getName());
            // 暂停线程
            Thread.yield();
        }
    }
}
// 测试类
public class Test {
    public static void main(String[] args) {
        FirstThread t1 = new FirstThread();
        SecThread t2 = new SecThread();
        t1.start();
        t2.start();
    }
}

// 运行结果,两个线程类都用了yield()方法,它们都还是可运行状态,如果没有相同更高优先级线程,它们互相交替执行
第一个线程的第1次运行Thread-0
第一个线程的第2次运行Thread-0
第一个线程的第3次运行Thread-0
第一个线程的第4次运行Thread-0
第二个线程的第1次运行Thread-1
第二个线程的第2次运行Thread-1
第二个线程的第3次运行Thread-1
第二个线程的第4次运行Thread-1
第二个线程的第5次运行Thread-1
第一个线程的第5次运行Thread-0 // 又是第一个线程

  在示例6中,调用了yield( )方法之后,当前线程并不是转人被阻塞状态,它可以与其他等待执行的线程竞争CPU资源,如果此时它又抢占到CPU资源,就会出现连续运行几次的情况。sleep( )方法与yield( )方法在使用时容易混淆,这两个方法之间的区别如下表所示。

sleep( )方法yield( )方法
使当前线程进入被阻塞状态将当前线程转入暂停执行状态
即使没有其他等待运行的线程,当前线程也会等待指定的时间如果没有其他等待的线程,当前线程会马上恢复执行
其他等待执行的线程的机会是均等的会将优先级相同或更高的线程运行
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值