深入理解Java多线程(一)

关于java多线程的概念以及基本用法:java多线程基础

1,停止线程

停止线程意味着在线程执行完之前停止正在做的操作,即立刻放弃当前的操作,这并不容易。停止线程可以用Thread.stop()方法,但是这个方法不安全,所以不建议使用,还有一个方法就是Thread.interrupt()方法,但是这个方法不会终止一个正在运行的线程,需要添加一个判断才可以完成线程的停止

1.1,停不下来的线程

  • public void interrupt()
    将调用者线程的中断状态设为true

Thread.interrupt()方法只是在当前线程中打了一个停止的标记,并不是直接将线程停止

class MyThread_1 extends Thread{

    @Override
    public void run() {
        super.run();
        for(int i=0;i<10000;i++) {
            System.out.println("i="+(i+1));
        }
    }

}

public class Demo1_7_1 {
    public static void main(String[] args) {
        try {
            MyThread_1 thread = new  MyThread_1();
            thread.start();
            Thread.sleep(200);
            thread.interrupt();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果:
这里写图片描述
从结果可以看到,使用thread.interrupt()线程并未停止

1.2,判断线程是否是停止状态

  • public static boolean interrupted
    只能通过Thread.interrupted()调用
class MyThread_2 extends Thread{
    @Override
    public void run() {
        super.run();
        for(int i=0;i<10000;i++) {
            System.out.println("i="+(i+1));
        }
    }
}

public class Demo1_7_2 {
    public static void main(String[] args) {
        try {
            MyThread_2 thread = new  MyThread_2();
            thread.start();
            Thread.sleep(2000);
            thread.interrupt();
            System.out.println("是否停止1?="+thread.interrupted());
            System.out.println("是否停止2?="+thread.interrupted());
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("end");
    }
}

运行结果:
这里写图片描述
当前线程是main并没有中断过,所以打印结果都是false

将main函数代码改为

        Thread.currentThread().interrupt();
        System.out.println("是否停止1?="+Thread.interrupted());
        System.out.println("是否停止2?="+Thread.interrupted());
        System.out.println("end");

结果为

是否停止1?=true
是否停止2?=false
end

为什么第二个值是false?这是因为第一次调用Thread.interrupted()返回当前线程中断状态,然后会将线程的中断状态设为false

  • public boolean isInterrupted()
    判断调用者线程的中断状态

讲main函数修改

        try {
        MyThread_2 thread = new  MyThread_2();
        thread.start();
        Thread.sleep(2000);
        thread.interrupt();
        System.out.println("是否停止1?="+thread.isInterrupted());
        System.out.println("是否停止2?="+thread.isInterrupted());
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("end");

运行结果是:

。。。
。。。。
i=9997
i=9998
i=9999
i=10000
是否停止1?=false
是否停止2?=false
end

很神奇这里返回结果都是false,想了半天,后来在网上查了资料明白是sleep函数的原因Thread.sleep(2000);休眠的是主线程,这里休眠的就是main函数,在这段时间里thread可能已经执行完了,所以thread.interrupt();也就起不到作用了,修改sleep函数时间,返回结果就都是true了

此方法作用:测试线程是否已经是中断状态,但是不会执行一次后将中断状态设置为false

1.3,停止线程–异常法

使用if语句判断线程是否是停止状态来控制后面的代码是否继续执行,但是无论是否停止线程,for循环外run方法里的代码都会执行,这里用throw new InterruptedException();来产生异常,从而结束线程,线程其余代码也不会执行了

class MyThread_3 extends Thread{

    @Override
    public void run() {
        super.run();
        try {
        for(int i=0;i<500000;i++) {
            if(this.isInterrupted()) {
            System.out.println("已经是停止状态了,我要退出");
            throw new InterruptedException();

            }
            System.out.println("i="+(i+1));
        }
        System.out.println("for下面");
        }catch(InterruptedException e) {
            System.out.println("进Mythread类run方法中的catch");
            e.printStackTrace();
        }

    }
}

public class Demo1_7_3 {
    public static void main(String[] args) {
        try {
            MyThread_3 thread = new MyThread_3();
            thread.start();
            Thread.sleep(2000);
            thread.interrupt();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("end");
    }
}

结果:

。。。。
。。。。。
i=366068
i=366069
i=366070
end
已经是停止状态了,我要退出
进Mythread类run方法中的catch
java.lang.InterruptedException
    at chapter_1.MyThread_3.run(Demo1_7_3.java:12)

1.4,停止线程–在Sleep状态

在sleep状态下停止某一线程会进入catch语句,并且清除停止状态值,使之变成false

class MyThread_4 extends Thread{

    @Override
    public void run() {
        super.run();
        try {
            System.out.println("run begin");
            Thread.sleep(200000);
            System.out.println("run end");
        } catch (Exception e) {
            // TODO: handle exception
            System.out.println("在沉睡中被停止进入catch"+this.isInterrupted());
            e.printStackTrace();
        }
    }
}

public class Demo1_7_4 {
    public static void main(String[] args) {
        try {
            MyThread_4 thread = new MyThread_4();
            thread.start();
            Thread.sleep(200);
            thread.interrupt();
        } catch (Exception e) {
            // TODO: handle exception
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("end");
    }

}

结果:

run begin
end
在沉睡中被停止进入catchfalse
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at chapter_1.MyThread_4.run(Demo1_7_4.java:10)

1.5,停止线程–暴力停止

所谓暴力停止就是最直接的方法了–stop(),这种方法直接让线程停止,但是这也会引来一些问题,比如线程的安全问题,不建议使用

1.6,停止线程–使用return

将方法interrupt()与return结合使用也可以实现停止线程

class MyThread_8 extends Thread{

    @Override
    public void run() {
        super.run();
        while(true) {
            if(this.isInterrupted()) {
                System.out.println("停止了!");
                return;
            }
            System.out.println("timer="+System.currentTimeMillis());
        }
    }
}

public class Demo1_7_8 {
    public static void main(String[] args) throws InterruptedException{
        MyThread_8 t = new MyThread_8();
        t.start();
        Thread.sleep(2000);
        t.interrupt();
    }
}

结果:

。。。
。。。
timer=1533907137644
timer=1533907137644
timer=1533907137644
timer=1533907137644
timer=1533907137644
timer=1533907137644
停止了!

1.7,yield方法

yield()方法作用是放弃当前CPU资源,让给其他线程去使用,但是放弃时间不确定

1.8,线程优先级

操作系统会对线程进行划分优先级,优先级高的线程会优先分配到资源,类似于现实中的VIP,Java将线程从1到10划分十个等级,默认优先级为NORM_PRIORITY,设置优先级用setPriority()
setPriority()源码:

    public final void setPriority(int i)
    {
        checkAccess();
        if(i > 10 || i < 1)
            throw new IllegalArgumentException();
        ThreadGroup threadgroup;
        if((threadgroup = getThreadGroup()) != null)
        {
            if(i > threadgroup.getMaxPriority())
                i = threadgroup.getMaxPriority();
            setPriority0(priority = i);
        }
    }
  • public final static int MIN_PRIORITY=1;
  • public final static int NORM_PRIORITY=5;
  • public final static int MAX_PRIORITY=10;

此外线程还具有继承性,若线程A启动线程B,则B具有A的优先级

1.9,守护线程

在Java线程中有两种线程,一种是用户线程一种是守护线程,我们常说的操作系统中并没有守护线程这一说,原因是Java是构建在JVM之上的。顾名思义,守护线程具有陪伴的意思,当进程中不存在非守护线程时,守护线程就会自动销毁。
Daemon作用是为了其他线程的运行提供便利服务,只有当最后一个非守护线程结束时,守护线程才会随着JVM一同结束工作,守护线程典型的例子就是GC

class MyThread_11 extends Thread{
    private int i=0;
    @Override
    public void run() {
        super.run();
        try {
            while(true) {
                i++;
                System.out.println("i="+(i));
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

public class Demo1_11 {

    public static void main(String[] args) {
        try {
            MyThread_11 thread = new MyThread_11();
            thread.setDaemon(true);
            thread.start();
            Thread.sleep(5000);
            System.out.println("守护线程离开了!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果:

i=1
i=2
i=3
i=4
i=5
守护线程离开了!

2018.9.9补充:
突然对this与Thread.currentThread()产生了疑问,下面来对这个区别来介绍一下:
创建一个MyObject类:

public class MyThread extends Thread{

    public MyThread() {
    }

    @Override
    public void run() {

        System.out.println("Thread.currentThread.getName= "
        +Thread.currentThread().getName());
        System.out.println("this.getName= "+this.getName());
    }

}

测试类:

public class Run {

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread t = new Thread(myThread);
        t.start();
    }
}

结果:

Thread.currentThread.getName= Thread-1
this.getName= Thread-0

显然这里this和Thread.currentThread()指向的不是同一个线程,看一下Thread源码:
这里写图片描述

Thread t = new Thread(myThread)这句传入的对象MyThread就是源码里的target对象,Thread类的构造方法会给线程一个默认的名字,从”Thread-0”开始
this.getName()其实就是target.getName(),返回的是执行MyThread myThread = new MyThread()的线程名,而Thread.currentThread().getName()返回的是t.getName(),返回的是Thread t = new Thread(myThread)这句创建的线程

猜你喜欢

转载自blog.csdn.net/qq_37438740/article/details/81556733