Java[学习总结]-多线程(四)之控制线程

1.Sleep()方法

sleep方法是Thread类的一个静态方法

	try{
	Thread.sleep(5* 60* 1000);
	}catch(InterruptedException ex){ }
//java.lang中提供的两种sleep()方式
    /**
     * Causes the currently executing thread to sleep (temporarily cease
     * execution) for the specified number of milliseconds, subject to
     * the precision and accuracy of system timers and schedulers. The thread
     * does not lose ownership of any monitors.
     *
     * @param  millis
     *         the length of time to sleep in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
   public static native void sleep(long millis) throws InterruptedException;
   
       /**
     * Causes the currently executing thread to sleep (temporarily cease
     * execution) for the specified number of milliseconds plus the specified
     * number of nanoseconds, subject to the precision and accuracy of system
     * timers and schedulers. The thread does not lose ownership of any
     * monitors.
     *
     * @param  millis
     *         the length of time to sleep in milliseconds
     *
     * @param  nanos
     *         {@code 0-999999} additional nanoseconds to sleep
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative, or the value of
     *          {@code nanos} is not in the range {@code 0-999999}
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
   public static void sleep(long millis, int nanos)
    throws InterruptedException {
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        sleep(millis);
    }

(1)Sleep方法意味着它会如期醒来(可运行状态),并不意味着它将返回的运行状态!
(2)尽管很多应用程序中把sleep0用作定时器,但是它仍然是一个无保障的方法,方法中的数字并不它不运行的准确时间,实际上往往>=休眠时间。

2.改变线程的优先级

2.1 优先级意义
(1)在大多数JVM中,调度程序程序使用基于优先级的抢先调度机制。当设计多线程应用程序时一.定不要依赖于线程优先级。因为这种操作时没有保障的,只能把线程优先级作为一种提高效率的方法。
(2)优先权不会导致死锁。优先级较低的线程仅仅是执行的频率较低。
(3)在绝大多数时间里,所有的线程都应该以默认的优先级运行。试图操作线程优先级通常是一种错误。

2.2 定义
(1)每个线程的默认优先级都与创建它的父线程具有相同的线程,在默认的情况下,main线程具有普通优先级。
(2)Thread类提供了setPriority(int newPriority)和getPriority0方法来设置和返回执行线程的优先级。
(3)虽然Java提供了10个优先级别,但是由于操作系统的支持并不能一一对应。通常采用三个静态常量来设置优先级,具有更好的移植性。这三个静态常量分别是:

        MyThread thread = new MyThread();
        Thread t = new Thread(thread);
        t.start();
        t.setPriority(MAX_PRIORITY);
        System.out.println(t.getPriority());

    /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;

3.线程让步

3.1 定义
yield()方法是Thread提供的一个静态方法,可以让当前正在执行的线程暂停转入就绪状态。等待下一次的重新调度。

Thread.yield();

3.2 注意事项
(1)实际上,当某个线程调用了yiel()方法后只有优先级相同或者高于当前线程的其他就绪状态的线程才会获得执行的机会。因此,yield方 法确实导致一个线程退出运行状态,并回到可运行状态也无法保证让步线程不会从其他线程中再次选中这个方法也是没有任何保障的。
(2)对于任何重要的控制或在调整应用时,都不能依赖于yield()。

4.Sleep()和yield()的区别

(1)sleep方法暂停当前线程后,会给其他线程机会执行,不会理会其他线程的优先级。但是yield方法只会给优先级相同或者更高的线程。
(2)sleep方法会将线程转入阻塞状态,直到经过阻塞时间才会转入就绪状态。而yield方法直接转入就绪状态。
(3)sleep方法会抛出InterruptedException异常,所以调用时需要显示捕获异常,yield方法不会抛出任何异常。
(4)sleep方法比yield方法具有更多的移植性,通常不依靠yield方法控制并发线程执行。

5.Join()线程

5.1 线程概念
Thread类的非静态方法join()让一个线程“加入”到另一线程的尾部。如果线程B在线程A完成工作之前不能做其他工作,则你会想让线程B“加入”线程 A。这就意味着线程B到A完成(进入死状态)之前不会变为可运行的。
假设我们在线程B的run()(也就是程序执行流)中开启了A线程,并且A线程对象调用了join()方法,那么此刻B线程就加在A线程的后面,必须等待A线程执行完后才会再运行!

Thread t= new Thread();
t.start();
这段代码在main方法中执行
t.join();

5.2 运行
当在某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被join方法加入的join线程完成为止。方便将一个大问题分解成小问题,一个线程完成一个小问题,当所有问题处理后再去调用主线程进一步操作。
(1) joi():等待被join的线程执行完成
(2) join(long millis):等待被join的线程时间最长millis毫秒
(3) join(long millis, int nanos):等待被join的线程的时间最长millis毫秒加上nanos微秒
注意:可能会分不清谁是join()线程,哪个线程加在了哪个线程的后面,哪个线程被迫等待,下面将根据代码解析情况

public class MyThread extends Thread{
    public static void main(String[] args) {
        Thread t1 = new Thread(new RunnableOne());
        t1.start();
    }
    @Override
    public void run() {
        super.run();
        for (int i =0;i<9;i++){
            System.out.println("MyThread线程开启");
        }
    }
}
public class RunnableOne implements Runnable{
    @Override
    public void run() {
        Thread t2 = new Thread(new RunnableTwo());
        t2.start();
//        try {
//            t2.join();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        for (int i=0;i<10;i++){
            System.out.println("RunnableOne:"+i);
        }
    }
}
public class RunnableTwo implements Runnable{
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            System.out.println("RunnableTwo:"+i);
        }
    }
}

只在主活动中开启RunnableOne对象线程,然后在Ruannable()方法执行流中开启RunnableTwo对象线程,由结果可见二者都在抢占CPU时间运行
在这里插入图片描述调用join()方法

public class MyThread extends Thread{
    public static void main(String[] args) {

        Thread t1 = new Thread(new RunnableOne());
        t1.start();
    }
    @Override
    public void run() {
        super.run();
        for (int i =0;i<9;i++){
            System.out.println("MyThread线程开启");
        }
    }
}
public class RunnableOne implements Runnable{
    @Override
    public void run() {
        Thread t2 = new Thread(new RunnableTwo());
        t2.start();
        try {
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i=0;i<10;i++){
            System.out.println("RunnableOne:"+i);
        }
    }
}
public class RunnableTwo implements Runnable{
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            System.out.println("RunnableTwo:"+i);
        }
    }
}

在结果中惊喜地发现,此刻完全是先执行的RunnableTwo线程对象,然而RunnableTwo恰好是在RunnableOne中执行的,由此可以做出判断:
假设我们在线程A的run()(也就是程序执行流)中开启了B线程,并且B线程对象调用了join()方法,那么此刻A线程就加在B线程的后面,必须等待A线程执行完后才会再运行!
在这里插入图片描述内存栈模拟:
在这里插入图片描述

6.后台线程

6.1 概念理解
有一种线程就是在后台运行,任务就是为其他线程提供服务,称为“后台线程”、“守护线程”。最主要的特征就是如果所有的前台线程都死亡,后台线程会自动死亡。

6.2 使用
调用Thread类的setDaemon(true)方法可以将指定线程设置为后台线程。该方法一定要在启动线程之前设置,否则会发生异常。
同时提供isDaemon0方法判断是否是后台线程。主线程一般默认为前台线程。前台线程创建的子线程默认是前台,后台线程创建的子线程默认是后台。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值