多线程(二)--线程的三个方法、线程停止、优先级和守护线程

一、线程的sleep()、yield()、join()方法

在多线程中,关于资源的方法,都是锁定的方法!!下面的几个方法就是锁定的方法。

1.sleep()---线程休眠方法

线程休眠:让线程暂缓执行一下,等到预计时间之后再恢复执行。线程休眠会交出CPU,并让CPU执行其它的任务。
sleep()不会释放锁,即如果当前线程持有对某个对象的锁,即使调用sleep(),其它线程也无法访问这个对象。(运行->阻塞

2.yield()---线程让步

暂停当前正在执行的线程对象,并执行其它线程。当前线程不一定交出CPU,具体释放CPU的时间由线程调度决定。如果此时有具有相同优先级的线程处于就绪状态,当前线程会交出CPU权限,让CPU去执行拥有相同优先级的线程。如果没有,则什么都不做。同样不会释放锁。但是yield方法不能控制具体交出CPU的时间。(运行->就绪
            调用yield()不会让线程进入阻塞状态,而是直接回到就绪状态,只需要等待重新获取CPU执行时间。

3.sleep VS yield

同:在当前线程中调用这两个方法,都会使当前线程暂停。执行其它的线程。不会释放锁。
异:sleep()可以控制暂停的时间,而yield()不能控制。
       yield()交出的CPU只能让CPU执行拥有相同线程优先级的其它线程。sleep()不考虑优先级。
       sleep()会使当前线程先阻塞,然后等待时间结束后才回到就绪状态。而yield()直接使当前线程回到就绪状态。
       sleep()抛出InterrupptedException异常,而yield()没有声明抛出任何异常。

4.join()--等待该线程终止

当前线程会阻塞等待其它线程执行完毕后再恢复执行。如果在当前线程(主线程或其它线程)中调用线程对象的join(),那么当前线程阻塞,直到线程对象的run()执行完毕,当前线程阻塞才解除。(运行->阻塞

package com.xunpu.a;


import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo4{

    public static void main(String[] args) throws InterruptedException {
        Mythread4 mythread=new Mythread4();
        Thread t=new Thread(mythread);
        t.start();
        t.join();
        System.out.println("代码结束");
    }
    public static void printTime(){
        Date date=new Date();
        DateFormat format=new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
        String time=format.format(date);
        System.out.println(time);
    }
}
class Mythread4 implements Runnable {

    public void run() {
        try {
            System.out.println("主线程睡眠开始时间:");
            Demo4.printTime();//静态方法,直接通过主类名调用
            Thread.sleep(2000);
            System.out.println("当前线程:"+Thread.currentThread().getName());
            System.out.println("线程结束的时间:");
            Demo4.printTime();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

二、线程的停止

1.线程停止的三种方式

1)代码控制:设置标记位,修改标记位,使线程终止。可以让线程正常终止。
2)使用stop()强制使线程退出,但是该方法不安全,已废弃。
    stop()为什么不安全?
     因为stop()会导致线程不会正确释放资源。stop()会解除由线程获取的所有锁定,当在一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会立即停止。
3)使用Thread类中的一个interrupt()中断线程。Thread.interrupt():将线程状态设置为中断状态。

interrupt()使线程停止的两种方式:

a.线程中没有wait、sleep、join方法时,调用线程的interrupt()只是将线程状态置为interrupt=true;
b.线程中有wait、sleep、join方法时,调用interrupt()会抛出InterruptException,在catch块中捕获该异常,然后退出。
    总结来说,调用线程的interrupt(),只是设置线程的中断标志为true,后续操作根据线程的状态采取不同的操作。如果线程处于阻塞状态(由sleep()、wait()、join()引起),那么设置线程中断标志为true后,还会抛出InterruptedException异常,并清除中断标志,重新设置中断标志为false。interrupt()只是改变中断状态,不会中断一个正在运行的线程。这个方法实际完成的是,给受阻塞的线程发出一个中断信号,这样受阻线程得以退出阻塞的状态。

interrupt()不会立即执行中断操作,只会给线程设置一个为true的中断标志(中断标志只是一个布尔类型的变量)。设置之后,根据线程当前的状态进行后续操作。如果当前线程为非阻塞状态,只修改中断标志为true;如果处于阻塞状态,如果是sleep()、wait()、join()引起,则抛出InterruptedException异常,且中断标志被程序会自动清除,重新设置为true。

2.具体代码实现

package com.xunpu.a;

/**
 * 使线程停止的方法
 * 方式一:设置标志位
 */
public class Demo5{
    public static void main(String[] args) throws InterruptedException {
        Mythread5 mythread=new Mythread5();
        Thread t=new Thread(mythread);
        t.start();
        Thread.sleep(2000);
        mythread.setFlag(false);
        System.out.println("代码结束");
    }

}
class Mythread5 implements Runnable {
    private boolean flag=true;
    public void run() {
        while(flag){
            System.out.println(Thread.currentThread().getName());
        }
    }
    public void setFlag(boolean flag){
        this.flag=flag;
    }
}

结果:(前2s一直输出):Thread-0
   'r          (2s时输出):代码结束

package com.xunpu.a;

/**
 * 使线程停止:调用Thread.interrupt()
 */
public class Demo6{
    public static void main(String[] args) throws InterruptedException {
        Mythread6 mythread=new Mythread6();
        Thread t=new Thread(mythread,"子线程A");
        t.start();
        Thread.sleep(3000);
        t.interrupt();
        System.out.println("代码结束");
    }

}
class Mythread6 implements Runnable {
    private boolean flag=true;
    public void run() {
        int i=1;
        while(flag){
            try {
                Thread.sleep(1000);//sleep引起阻塞
                boolean bool=Thread.currentThread().isInterrupted();//中断,bool=true;未中断,bool=false.
                //3s时,中断造成的异常立即被捕获到,不再执行try下面的代码。
                if(bool){
                    System.out.println("非阻塞情况下执行该操作。。。线程状态"+bool);
                    break;
                }
                System.out.println("第"+i+"次执行,线程名称为:"+Thread.currentThread().getName());
                i++;
            } catch (InterruptedException e) {
                System.out.println("退出了");//在这里会退出阻塞状态,且中断标志被系统自动清除,并重新设置为false.
                boolean bool=Thread.currentThread().isInterrupted();//false
                System.out.println(bool);
                return;
            }
        }
    }

}

结果:(1s时输出):第1次执行,线程名称为:子线程A
          (2s时输出):第2次执行,线程名称为:子线程A
          (3s时输出):代码结束
                                    退出了
                                     false

三、线程的优先级(1~10)

1.含义

线程的优先级越高,越有可能优先执行,仅仅是有可能而已。

2.与线程优先级有关的几个函数(Thread类提供)

	a.设置线程的优先级  public void setPriority(int newPriority);
	b.获取线程的优先级 public int getPriority();

3.设置优先级可以通过Thread类的几个常量来决定

	a.最高优先级   Thread.MAX_PRIORITY=10
	b.中等优先级   Thread.NORM_PRIORITY=5
	c.最低优先级    Thread.MIN_PRIORITY=1

说明:1)主方法是中等优先级。一般的线程如果没有设置优先级,那么会默认是5.

2)线程具有继承性。如果在一个线程(父线程)中启动另一个线程(子线程),那么子线程的线程优先级和父线程相同。但是子线程的优先级可以修改。
注意:优先级为10的不一定先执行,这和操作系统有关。在某些操作系统中,优先级并不会生效!!

package com.xunpu.a;

public class Priority {
    public static void main(String[] args) {
        MyThread7 myThread1=new MyThread7();
        Thread t1=new Thread(myThread1,"ThreadA");
        Thread t2=new Thread(myThread1,"ThreadB");
        Thread t3=new Thread(myThread1,"ThreadC");
        t3.setPriority(Thread.MAX_PRIORITY);
        t2.setPriority(Thread.NORM_PRIORITY);//5
        t1.setPriority(Thread.MIN_PRIORITY);//1
        t3.start();
        t1.start();
        t2.start();
        System.out.println(Thread.currentThread().getPriority());//当前线程是主线程,默认是5。

    }
}
class MyThread7 implements Runnable{
    public void run(){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("当前线程为:"+Thread.currentThread().getName()+" 优先级为:"+Thread.currentThread().getPriority());
        Thread t=new Thread();
        t.start();
        int priority=t.getPriority();
        System.out.println(" 子线程的优先级是:"+priority);
    }
}

四、守护线程

1.定义

守护线程是一种特殊的线程,也叫做后台线程。它属于是一种陪伴线程。如: 垃圾回收线程
只要当前JVM进程中存在任何一个非守护线程没有结束,守护线程就在工作;只有当最后一个非守护线程结束时,守护线程才会随着JVM一同停止工作。(生命周期

2.Java中的两种线程

用户线程和守护线程。可以isDaemon()方法来区别它们:如果返回false,则说明该线程是“用户线程”;否则就是“守护线程”。

package com.xunpu.a;

/**
 * 守护进程和用户进程
 */
public class Demo8 {
    public static void main(String[] args) throws InterruptedException {
        //创建守护线程
        //  A company=new A();
        Thread t1=new Thread(new A(),"线程A");//此时t1默认是用户线程
        t1.setDaemon(true);//设置t1线程是守护线程,必须在t1启动之前设置。
        t1.start();
        //创建用户线程
        Thread t2=new Thread(new A(),"线程B");
        t2.start();
        Thread.sleep(3000);
        t2.interrupt();
        Thread.sleep(1000);
        System.out.println("代码结束");

    }
}

class A implements Runnable {
    private int i;
    public void run() {
        while (true) {
            try {
                i++;
                System.out.println("线程名称:" + Thread.currentThread().getName() + ",i=" + i + "是否是守护线程" + Thread.currentThread().isDaemon());
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("线程" + Thread.currentThread().getName() + "中断了");
                break;
            }
        }
    }
}

 结果:

        线程名称:线程B,i=1是否是守护线程false
        线程名称:线程A,i=1是否是守护线程true
(1s时输出)线程名称:线程B,i=2是否是守护线程false
        线程名称:线程A,i=2是否是守护线程true
(2s时输出)线程名称:线程A,i=3是否是守护线程true
        线程名称:线程B,i=3是否是守护线程false
(3s时输出)线程线程B中断了
        线程名称:线程A,i=4是否是守护线程true
(4s时输出)代码结束

注意:

1)只有在线程启动前(即调用start()前),才能通过Thread.setDaemon(true)把它设置为后台线程(守护线程)。如果在线程启动后,再调用这个线程的setDaemon()方法,会抛出IllegalThreadStateException异常。

2)由用户线程(也叫做前台线程)创建的线程默认情况下仍然是前台线程,由守护线程(后台线程)创建的线程默认情况下仍然是守护线程(后台线程)。


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值