java 多线程(关于Thread的讲解)


学习来源于b站 https://www.bilibili.com/video/av82219418
自己仅作 java 多线程的记录,看视频主要还是看书看不下去了…
然后推荐大家看看《JAVA并发编程实践》

Thread 介绍

Thread 生命周期图

在这里插入图片描述

  • java 应用程序的main函数是一个线程,是被jvm启动时调用,线程的名字叫main
  • 实现一个线程,必须创建Thread 实例,override run方法,并且调用start方法
  • 在JVM启动后,实际上有多个线程,但是至少有一个非守护线程
  • 当你调用一个线程start方法的时候,此时至少有两个线程,一个是调用你的线程,还有一个执行run方法的线程

下面代码观察,Thread 线程用 run 执行和 start 执行的区别

public static void main(String[] args) {

       new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("start:"+Thread.currentThread().getName()); // 当前线程名
           }
       }).start();

       new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("run:"+Thread.currentThread().getName()); // main 线程
           }
       }).run(); // 调用run方法,仅仅是实例对象调用
   }

Thread 构造方法介绍

  • 创建线程对象Thread,默认有一个线程名,以Thread-开头,以0开始计数,具体实现参考以下源码
    public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); }
  • 如果构造线程对象时,未传入ThreadGroup,Thread 会默认获取父线程的ThreadGroup 作为该线程的ThreadGroup , 此时子线程和父线程在同一个ThreadGroup中,参考以下源码
    /* If the security doesn't have a strong opinion of the matter use the parent thread group. */ if (g == null) { g = parent.getThreadGroup(); }
  • 构造Thread 的时候传入stacksize 代表着该线程占用stack大小,如果没有指定stacksize 的大小,默认是0,0代表着会忽略该参数,该参数会被JNI函数去使用。需注意:该参数有一些平台有效,有些平台无效。

Daemon 线程

守护线程

Thread thread = new Thread(() -> {

        Thread innerThread = new Thread(() -> {

            while(true){
                System.out.println("do something...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        innerThread.setDaemon(true); // 设置为守护线程
        innerThread.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });

    thread.start();
}

作用:当你线程调用其他线程的时候,你的线程结束时,设置为守护线程会随着外面的线程而结束。

join 方法

等待当前线程执行完后,主线程继续执行的意思。

public static void testJoin() throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                Thread.sleep(10000);
            }
        });
        t.start();
        t.join();

        System.out.println("finish...");
    }

上述例子,如果不添加t.join(); 的话,里面会把输出语句打印出来,但是添加后,等上面的线程执行完毕后,在执行主线程。当我们统计其他线程的时候,就需要用到join。

线程结束

方式1,利用标记的方式

public class ThreadStop extends Thread {

    private volatile boolean start = true;

    @Override
    public void run() {

        while(start){
			// TODO
        }
    }

    public void shutdown(){
        this.start = false;
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadStop threadStop = new ThreadStop();
        threadStop.start();
        Thread.sleep(1000);
        threadStop.shutdown();
    }
}

方式2:利用interrupt方法

public class ThreadStop extends Thread {

    @Override
    public void run() {

        while(true){
             if(Thread.interrupted()){
                break; // return
            }
        }
    }


    public static void main(String[] args) throws InterruptedException {
        ThreadStop threadStop = new ThreadStop();
        threadStop.start();
        Thread.sleep(1000);
        threadStop.interrupt();
    }
}

暴力解决线程

无论标记,还是打断的方式,都需要在某一处判断,但是多数时候,block的状态,我们才想结束;
而jdk 提供的stop()方法已经过期了。

之前守护线程提起过,如果我们主线程被结束的话,守护进程也是被jvm关闭的。

/**
 * @Author: shengjm
 * @Date: 2020/2/5 15:48
 * @Description: 让传入的线程成为守护线程,这样关闭线程的时候,关闭守护线程
 */

public class ThreadCloseForce {

    private boolean finished = false;

    private Thread executeThread;

    public void execute(Runnable task){
        executeThread = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread runner = new Thread(task);
                runner.setDaemon(true);
                runner.start();
                try {
                    runner.join();
                    finished = true;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        executeThread.start();
    }

    public void shutdown(long mills){
        long currentTime = System.currentTimeMillis();
        while(!finished){
            if(System.currentTimeMillis() - currentTime > mills){
                System.out.println("超时啦~");
                executeThread.interrupt();
                break;
            }

            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }
        }

        finished = false;

    }

    public static void main(String[] args) {
        ThreadCloseForce threadCloseForce = new ThreadCloseForce();
        long start = System.currentTimeMillis();
        threadCloseForce.execute(()->{
//            while(true){
//                //TODO
//            }
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        threadCloseForce.shutdown(10000);
        long end = System.currentTimeMillis();
        System.out.println("总共消耗时间"+(end-start));

    }
}
发布了46 篇原创文章 · 获赞 6 · 访问量 2611

猜你喜欢

转载自blog.csdn.net/renguiriyue/article/details/104160794