Thread类

五迷三道 提交于 2019-12-06 17:38:27

一、线程的编写方式

①继承Thread类

②实现Runnable接口(推荐使用,JAVA是单继承,如果该类已经继承了一个类了,那么就只能使用实现接口的方式)

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("继承Thread类");
    }
}
class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println("实现Runnable接口");
    }
}
public class Test{
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
        Thread thread=new Thread(new MyRunnable());
        thread.start();
        System.out.println("main end");
    }
}

结果:

 

二、this和Thread.currentThread()各种方法的区别

this:当前对象

Thread.currentThread():当前线程

currentThread()

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("this.currentThread:"+this.currentThread());
        System.out.println("Thread.currentThread:"+Thread.currentThread());
    }
}
public class Test{
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        Thread thread=new Thread(myThread);
        thread.start();
        myThread.start();
    }
}

结果:

 

可以很明显地看到,无论是用一个线程包含另一个线程启动,还是一个线程单独启动,两个方法所得到当前线程都是一样的

注:这里面的main并不是指当前线程的名字

结论:两个方法都是获取当前线程,近乎等价

 

②getName()

class MyThread extends Thread{
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println("this.getName:"+this.getName());
            System.out.println("Thread.currentThread.getName:"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Test{
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread=new MyThread();
        Thread thread=new Thread(myThread);
        thread.start();
        Thread.sleep(1000);
        myThread.start();
        System.out.println("main线程已经结束");
    }
}

结果:

分析:

1)在源码中可以看见如下代码

线程的名字在调用构造函数的时候就已经确定,nextThreadNum()函数使用的是一个从0开始累加的一个static变量

2)结合结果和代码,可以推断出myThread的名字是Thread-0,而thread的名字是Thread-1。第一个开始运行的线程thread包裹了myThread,this指的是当前对象,所以this.getName()永远都是myThread的名字。而Thread.currentThread().getName()指的是外部线程(thread包裹了myThread)thread的名字。第二个运行的线程myThread中Thread.currentThread().getName()为Thread-0的原因是因为该线程没有被包裹(可以看见主线程已经早早结束),所以就是本身Thread-0

结论:this.getName()指的是当前对象的名字,Thread.currentThread().getName():①当有外部线程时,指的是外部线程的名字 ②没有外部线程时,指的是当前线程的名字

 

③isAlive()

class MyThread extends Thread{
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println("this.isAlive:"+this.isAlive());
            System.out.println("Thread.currentThread.isAlive:"+Thread.currentThread().isAlive());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Test{
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread=new MyThread();
        myThread.run();
        Thread.sleep(1000);
        myThread.start();
        Thread.sleep(1000);
        Thread thread=new Thread(myThread);
        thread.start();
        System.out.println("main线程已经结束");
    }
}

结果:

 结论:判断线程是否存活

 

④getId()

class MyThread extends Thread{
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println("this.getId:"+this.getId());
            System.out.println("Thread.currentThread.getId:"+Thread.currentThread().getId());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Test{
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread=new MyThread();
        myThread.run();
        Thread.sleep(1000);
        myThread.start();
        Thread.sleep(1000);
        Thread thread=new Thread(myThread);
        thread.start();
        System.out.println("main线程已经结束");
    }
}

结果:

 结论:获取线程的唯一标识

 

interrupt、interrupted、isInterrupted

class ThreadA extends Thread{
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            System.out.println("i="+i);
        }
    }
}
public class Test{
    public static void main(String[] args) {
        ThreadA threadA = new ThreadA();
        Thread thread = new Thread(threadA);
        thread.start();
        thread.interrupt();
        System.out.println(thread.isInterrupted());
        System.out.println(thread.interrupted());
        System.out.println(thread.interrupted());
        Thread.currentThread().interrupt();
        System.out.println(thread.interrupted());
        System.out.println(thread.interrupted());
    }
}

结果:

分析:thread.interrupted()前两次调用都为false,是因为其检测的是main线程(当前线程)是否中断,所以当主线程使用Thread.currentThread().interrupt()设置中断标志过后,再调用时第一次为true,最后一次为false则是因为调用一次后会清除中断标志

class ThreadA extends Thread{
    @Override
    public void run() {
        System.out.println(this.isInterrupted());
        if(!this.interrupted()){
            for(int i=0;i<10;i++){
                System.out.println("i="+i);
            }
        }else{
            System.out.println("该线程已经设置中断");
            System.out.println(this.isInterrupted());
        }
    }
}
public class Test{
    public static void main(String[] args) {
        ThreadA threadA = new ThreadA();
        threadA.start();
        threadA.interrupt();
    }
}

结果:

分析:第二次为false,是因为interrupted会清除中断标志,在主线程调用interrupt(),程序继续执行,是因为该方法并不会中断线程,仅仅是设置一个中断标志

总结:interrupt()给调用该方法的线程实例设置中断标志(并不会使线程停止), interrupted()是针对当前线程而言(调用后会清除中断标志),isInterrupted()指的是你调用该方法的那个线程实例

 

三、中止、暂停、恢复线程

①中止线程

1)return与抛出异常

class ThreadA extends Thread{
    @Override
    public void run() {
        try{
            if(this.interrupted()){
                //return;
                throw new InterruptedException();
            }
            System.out.println("线程还未中断");
        }catch (Exception e){
            System.out.println("捕获中断异常");
        }
    }
}
public class Test{
    public static void main(String[] args) {
        ThreadA threadA = new ThreadA();
        threadA.start();
        threadA.interrupt();
    }
}

结果:

分析:抛出异常return能终止线程

2)sleep与interrupt

class ThreadA extends Thread{
    @Override
    public void run() {
        try{
            Thread.sleep(2000);
            System.out.println("线程还未中断");
        }catch (Exception e){
            System.out.println("捕获中断异常");
            System.out.println(this.interrupted());
        }
    }
}
public class Test{
    public static void main(String[] args) throws InterruptedException {
        ThreadA threadA = new ThreadA();
        threadA.start();
        Thread.sleep(1000);
        threadA.interrupt();
    }
}

结果:

分析:interrupted()为false是因为进入catch语句会清除停止状态值,线程先睡眠后设置中断,会导致线程中断

class ThreadA extends Thread{
    @Override
    public void run() {
        try{
            for(int i=0;i<10;i++){
                System.out.println(i);
            }
            Thread.sleep(1000);
            System.out.println("线程还未中断");
        }catch (Exception e){
            System.out.println("捕获中断异常");
        }
    }
}
public class Test{
    public static void main(String[] args){
        ThreadA threadA = new ThreadA();
        threadA.start();
        threadA.interrupt();
        System.out.println("main线程结束");
    }
}

结果:

 分析:线程先中断后睡眠,也会导致线程中断

3)stop

class ThreadA extends Thread{
    @Override
    public void run() {
        try{
            this.stop();
            System.out.println("线程还在执行");
        }catch (ThreadDeath e){
            System.out.println("捕获异常");
            e.printStackTrace();
        }
    }
}
public class Test{
    public static void main(String[] args){
        ThreadA threadA = new ThreadA();
        threadA.start();
    }
}

结果:

 分析:线程stop会抛出ThreadDeath异常

class ThreadA extends Thread{
    @Override
    public void run() {
        try{
            for(int i=0;i<50000;i++){
                System.out.println(i);
            }
            System.out.println("线程还在执行");
        }catch (ThreadDeath e){
            System.out.println("ThreadA捕获异常");
            e.printStackTrace();
        }
    }
}
public class Test{
    public static void main(String[] args){
        ThreadA threadA = new ThreadA();
        threadA.start();
        try{
            Thread.sleep(100);
            threadA.stop();
        }catch (ThreadDeath e){
            System.out.println("main捕获异常");
            e.printStackTrace();
        }catch (Exception e){

        }
    }
}

结果:

分析:虽然是在主线程调用该方法的,但是依旧是ThreadA抛出异常

结论:中止线程一共有4种方法:①return②stop③抛出异常④interrupt和sleep组合使用

 

②暂停、恢复线程

 

class ThreadA extends Thread{
    public long i;
    @Override
    public void run() {
        while(true){
            i++;
        }
    }
}
public class Test{
    public static void main(String[] args) throws InterruptedException {
        ThreadA threadA = new ThreadA();
        threadA.start();
        Thread.sleep(1000);
        threadA.suspend();
        System.out.println(System.currentTimeMillis()+";"+threadA.i);
        Thread.sleep(1000);
        System.out.println(System.currentTimeMillis()+";"+threadA.i);
        threadA.resume();
        Thread.sleep(5000);
        System.out.println(System.currentTimeMillis()+";"+threadA.i);
    }
}

结果:

结论:暂停和重启线程

 

四、线程切换

①yield

并不是马上切换(放弃cpu资源)

 

五、线程优先级

线程的优先级:从1-10,1的优先级最低,10的优先级最高

①setPriority

②getPriority

cpu有概率把资源先给优先级高的线程

 

六、守护线程

①setDaemon

class ThreadA extends Thread{
    @Override
    public void run() {
        while(true){
            try {
                System.out.println("还在执行");
                this.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Test{
    public static void main(String[] args) throws InterruptedException {
        ThreadA threadA = new ThreadA();
        threadA.setDaemon(true);
        threadA.start();
        Thread.sleep(5000);
        System.out.println("main线程结束");
    }
}

结果:

 结论:当线程设置为守护线程后,当非守护线程都结束时,守护线程会随着JVM一起结束

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!