当前位置:首页 > Java技术 > 深入理解JAVA多线程---多线程的常用操作

深入理解JAVA多线程---多线程的常用操作

2022年11月05日 22:20:33Java技术12

线程启动(start())

上文中已将提到了线程的几种创建方法,当线程创建后调用start()方法就可以启动线程了.

	//线程类继承Runnable接口
    static class MyThread implements Runnable{
     

        @Override
        public void run() {
     
            System.out.println("线程启动了!");
        }
    }
    //线程启动
    public static void startThread(){
     
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
    }
    public static void main(String[] args) {
     
        startThread();
    }

深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记

线程名称的设置和获取

线程名字在创建的时候设置,获取是通过getName()方法获取

//线程名称设置和获取
    public static void getAndSetThreadName(){
     
        MyThread myThread = new MyThread();
        //线程名字在创建的时候命名
        Thread thread = new Thread(myThread,"线程1");
        thread.start();
        //通过getName()方法获取线程名字
        System.out.println("线程名字:"+thread.getName());
    }
    public static void main(String[] args) {
     
        //startThread();
        getAndSetThreadName();
    }

深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记

线程休眠(sleep())

sleep(millis)方法会让线程休眠一段时间

static class MyThread implements Runnable{
     

        @Override
        public void run() {
     
            try {
     
                //System.out.println("线程启动了!");
                System.out.println("begin time = " + System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("end time = " + System.currentTimeMillis());
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }
    }
    //线程启动
    public static void startThread(){
     
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
    }
    public static void main(String[] args) {
     
        startThread();
    }

深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记
运行结果如图,线程暂停了两秒继续执行.

线程停止

在JAVA中线程停止有3种方法:

1. 使用退出标志使线程正常退出.


public class ThreadFlag extends Thread
{
     
    public volatile boolean exit = false;
 
    public void run()
    {
     
        while (!exit);
    }
    public static void main(String[] args) throws Exception
    {
     
        ThreadFlag thread = new ThreadFlag();
        thread.start();
        sleep(5000); // 主线程延迟5秒
        thread.exit = true;  // 终止线程thread
        thread.join();
        System.out.println("线程退出!");
    }
}

2. 使用stop()方法强行终止线程,但这个方法不推荐使用,可能发生不可预料的结果.

3. 使用interrupt()方法中单线程.

这里着重讲interrupt()方法
为了更好地理解interrupt中断的原理先举一个例子:

	static class MyThread1 implements Runnable{
     

        @Override
        public void run() {
     
            for (int i = 0; i < 500; i++) {
     
                System.out.println("i = " + i);
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
     
        MyThread1 myThread1 = new MyThread1();
        Thread thread = new Thread(myThread1);
        thread.start();
        Thread.sleep(2);
        thread.interrupt();
        System.out.println("********************************");
    }

上面代码的运行结果如图
深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记
在i=56后输出了**********,意味着主线程休眠的2ms里for语句执行了57次,然而在调用thread.interrupt()函数后for循环依旧没有停止,说明interrupt并没有让线程停止,只是给线程加了一个中断标志.那究竟怎样让线程停止呢?
在学习如何停止线程之前我们需要先了解两个判断线程是否为停止状态的函数

- public static boolean interrupted() : 测试currentThread()是否已经中断.

先来理解一下interrupted()函数的细节:

	static class MyThread1 implements Runnable{
     

        @Override
        public void run() {
     
            for (int i = 0; i < 500; i++) {
     
                System.out.println("i = " + i);
            }
        }
    }
	public static void main(String[] args) throws InterruptedException {
     
        MyThread1 myThread1 = new MyThread1();
        Thread thread = new Thread(myThread1);
        thread.start();
        Thread.sleep(1000);
        thread.interrupt();
        //Thread.currentThread().interrupt();
        System.out.println("线程中断标志1 :" + Thread.interrupted());
        System.out.println("线程中断标志2 :" + Thread.interrupted());
    }

深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记
这是第一次运行的结果,然后去掉上面注释行Thread.currentThread().interrupt();
深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记
这证明了interrupted()方法:测试当前线程是否已经中断.这个当前线程是main,在第一次运行过程中main没有被中断因此输出始终未false,第二次运行加了中断main线程的代码后,输出为true,但为什么第二次输出线程的标志时为false呢? 查询interrupted()方法在官方的文档中解释:

测试当前线程是否已经中断.线程的中断状态由该方法清除.由此可知第二次输出false是因为第一次调用该方法的时候中断状态被清除了,所以输出false.

- public boolean this.isInterrupt() : 测试this关键字所在类对象是否已经中断.

接着是isInterrupted() 从方法声明中就可以看出它不是static()方法,作用于调用这个方法的对象.

	static class MyThread1 implements Runnable{
     

        @Override
        public void run() {
     
            for (int i = 0; i < 500; i++) {
     
                System.out.println("i = " + i);
            }
        }
    }
 	public static void main(String[] args) throws InterruptedException {
     
        MyThread1 myThread1 = new MyThread1();
        Thread thread = new Thread(myThread1);
        thread.start();
        Thread.sleep(2);
        thread.interrupt();
        System.out.println("线程中断标志1 :" + thread.isInterrupted());
        System.out.println("线程中断标志2 :" + thread.isInterrupted());
    }

深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记
从运行结果来看,isInterrupted()并不会清除状态标志,输出两个true.
综上所述,这两个方法区别如下:

  1. this.interrupted() : 测试当前线程是否已经是中断状态,执行后具有清除状态标志,置为false的功能.
  2. this.isInterrupted() :测试线程Thread对象是否已经是中断状态,不清除状态标志.

说了这么多那到底怎样才能停止一个线程呢?稍安勿躁,想要真正了解一个知识,你要从头到尾的去研究,才能更好的掌握,而不是浅显的明白.废话不多说接下来就是停止线程的具体操作:
我们在了解了上面两个方法之后,就可以通过判断线程的中断状态来对线程进行停止.直接上代码:

	static class MyThread1 implements Runnable{
     

        @Override
        public void run() {
     
            for (int i = 0; i < 50000; i++) {
     
                if (Thread.interrupted()){
     
                    System.out.println("线程是停止状态!退出循环");
                    break;
                }
                System.out.println("i = " + i);
            }
            System.out.println("for 后面的语句");
        }
    }
    public static void main(String[] args) throws InterruptedException {
     
        MyThread1 myThread1 = new MyThread1();
        Thread thread = new Thread(myThread1);
        thread.start();
        Thread.sleep(1);
        thread.interrupt();
        System.out.println("线程中断标志1 :" + thread.isInterrupted());
        System.out.println("线程中断标志2 :" + thread.isInterrupted());
    }

深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记
由此就可以实现线程的中断了,但是我们发现一个问题,interrupt()函数只是添加了一个状态,通过判断状态退出循环,但是for循环后面的语句还是会执行,此时还不是真正意义上的线程停止.接下来就要借助异常了!

interrupt() + 异常 实现线程停止

	static class MyThread1 implements Runnable{
     
        @Override
        public void run() {
     
            try {
     
                for (int i = 0; i < 50000; i++) {
     
                    if (Thread.interrupted()){
     
                        System.out.println("线程是停止状态!");
                        throw new InterruptedException();
                    }
                    System.out.println("i = " + i);
                }
                System.out.println("for 后面的语句");
            } catch (InterruptedException e) {
     
                System.out.println("进入catch,线程停止!");
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
     
        MyThread1 myThread1 = new MyThread1();
        Thread thread = new Thread(myThread1);
        thread.start();
        Thread.sleep(1);
        thread.interrupt();
    }

深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记
值得一提的是 在线程interrupt()之后调用sleep(),线程就会抛出异常而停止

	static class MyThread1 implements Runnable{
     

        @Override
        public void run() {
     
            try {
     
                System.out.println("线程开始!休眠两秒");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
     
        MyThread1 myThread1 = new MyThread1();
        Thread thread = new Thread(myThread1);
        thread.start();
        Thread.sleep(1000);
        System.out.println("线程中断");
        thread.interrupt();
    }

运行结果:
深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记
程序是先让线程休眠然后在休眠过程中打上中断标志,可以看出抛出了异常,那么先打上中断标志再让线程休眠呢?上代码!

	static class MyThread1 implements Runnable{
     

        @Override
        public void run() {
     
            try {
     
                System.out.println("线程开始!休眠两秒");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
     
        MyThread1 myThread1 = new MyThread1();
        Thread thread = new Thread(myThread1);
        thread.start();
        System.out.println("线程中断");
        thread.interrupt();
    }

运行结果:
深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记
由此可以看出 只要interrupt()遇到sleep()就会抛出异常.

线程让步(yield())

yield()方法的作用是放弃当前CPU资源,让其他任务去占用CPU执行时间,放弃的时间是不确定的,有可能刚刚放弃就又获得了CPU时间片.

	static class MyThread1 implements Runnable{
     
        @Override
        public void run() {
     
            long beginTime = System.currentTimeMillis();
            int count = 0;
            for (int i = 0; i < 5000000; i++) {
     
                //Thread.yield();
                count += i;
            }
            long endTime = System.currentTimeMillis();
            System.out.println("任务用时:" + (endTime - beginTime)+"毫秒");
        }
    }
    public static void main(String[] args) throws InterruptedException {
     
        MyThread1 myThread1 = new MyThread1();
        Thread thread = new Thread(myThread1);
        thread.start();
    }

第一次运行,没有线程让步,被注释掉了:
深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记
运算很快
第二次把注释去掉,每次for循环都加上线程让步:
深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记
很明显,CPu资源让给其他资源,速度变得很慢.

线程的优先级(setPriority())

在操作系统中,线程是可以设置优先级的,优先级越高的线程获得的CPU资源就越多,也就是让优先级更高的线程获得更多的时间片。
设置优先级的方法setPriority()。
先看一下setPriority()方法的源码:

public final void setPriority(int newPriority) {
     
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
     
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
     
            if (newPriority > g.getMaxPriority()) {
     
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

在JAVA中,线程的优先级分为1~10个等级,如果数值小于1或者大于10就会抛出异常IllegalArgumentException()。
优先级有几个特性:

  1. 优先级具有规律性,优先级大的在测试数值较大比如进行循环的时候,优先级大就先执行完,呈现规律性。
  2. 优先级具有随机性,比如优先级设置为5和6的两个线程运行结果也有可能是优先级为5的先执行完
    上面总结一下就是:

优先级高的往往先执行完,但这个结果不是绝对的。

优先级对运行时间的影响:

	static class MyThread implements Runnable{
     
        private int count = 0;

        public int getCount(){
     
            return count;
        }
        @Override
        public void run() {
     
            while (true){
     
                count++;
            }
        }
    }
	static class MyThread1 implements Runnable{
     
        private int count = 0;

        public int getCount(){
     
            return count;
        }
        @Override
        public void run() {
     
            while (true){
     
                count++;
            }
        }
    }
	public static void main(String[] args) throws InterruptedException {
     
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.setPriority(1);
        thread.start();

        MyThread1 myThread1 = new MyThread1();
        Thread thread1 = new Thread(myThread1);
        thread1.setPriority(10);
        thread1.start();

        Thread.sleep(2000);

        System.out.println("thread = " + myThread.getCount());
        System.out.println("thread = " + myThread1.getCount());
    }
    

深入理解JAVA多线程---多线程的常用操作 _ JavaClub全栈架构师技术笔记

可见优先级高的运行速度就越快,几乎每次运行后thread1的值都比thread大,就是因为thread1优先级更高,获取了更多的时间片。

作者:莫秃
来源链接:https://blog.csdn.net/weixin_45758058/article/details/112194962

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/68065.html

分享给朋友: