Java Thread知识点总结

2019-05-20  本文已影响0人  沉淀之际

简介

什么是线程

进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。
线程:一个线程不能独立的存在,它必须是进程的一部分。

线程的生命周期
生命周期

实现方式

大家可能在面试过程中、文章中或者书上看到过“实现线程有几种方式?”这样的问题,基本都是千篇一律的说两种方式:1、继承Thread重写run方法;2、实现Runnable接口。其实这里是有问题的,总所周知在Java中使用Thread表示线程的,所以实现Thread只有一种方式:那就是构造Thread类。而实现线程的执行单元有两种方式:1、继承Thread重写run方法;2、实现Runnable接口的run方法,并将Runnable实例作为构造Thread的参数。

API讲解

构造函数
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(String name) {
        init(null, null, name, 0);
    }

    public Thread(ThreadGroup group, String name) {
        init(group, null, name, 0);
    }

    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }

    public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }

    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }
    
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null);
    }
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
    ...
    }

强烈建议:在构造线程的时候为线程取一个有特殊意义的名字,有助于问题的排查和线程的跟踪(特别是在线程比较多的程序中)。

Thread.sleep和TimeUnit

sleep()方法导致程序暂停执行指定的时间,让出cpu给其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。

sleep是一个静态方法,有两个重载方法,其中一个需要传入毫秒数,另一个既需要毫秒数也需要纳秒数。

public static void sleep(long millis)
public static void sleep(long millis, int nanos)

TimeUnit是JDK1.5以后引入的,其对sleep有更好的封装性,能更好地、更精准地控制。

TimeUnit.HOURS.sleep(1);
TimeUnit.MUNUTES.sleep(1);
TimeUnit.SECONDS.sleep(1);

强烈建议:用TimeUnit代替Thread.sleep,因为sleep能做的事,TimeUnit都能做并且功能更强大。

Thread.yield

yield方法属于一种启发式的方法,其会提醒调度器我愿意放弃当前CPU资源。如果CPU资源不紧张,则会忽略这种提醒。如果生效,会使当前线程从Running状态切换到Runnable状态。

new Thread(() -> {
    Thread.yield();
    System.out.println("yield");
  }
).start()
yield和sleep区别
join

join()方法是Thread类中的一个方法,该方法的定义是等待该线程终止。其实就是join()方法将挂起调用线程的执行,直到被调用的对象完成它的执行。join与sleep一样是一个可中断的方法。

ThreadTest test  =new ThreadTest();
ThreadTest test2  =new ThreadTest();
test.setName("one");
test2.setName("two");
Thread t1 = new Thread(test);
Thread t2 = new Thread(test2);
t1.start();
/**
* 主线程向下转时,碰到了t1.join(),t1要申请加入到运行中来,就是要CPU执行权。
* 这时候CPU执行权在主线程手里,主线程就把CPU执行权给放开,陷入冻结状态。
* 活着的只有t1了,只有当t1拿着执行权把这些数据都打印完了,主线程才恢复到运行中来
*/
//join 方法 确保 t1执行之后 执行t2
t1.join();
t2.start();
join和CountDownLatch区别
interrupt、interrupted、isInterrupted
interrupt

interrupt()方法: 作用是中断线程。

interrupted和isInterrupted
        System.out.println("Main Thread is interrupted? " + Thread.interrupted());
        Thread.currentThread().interrupt();
        System.out.println("Main Thread is interrupted? " + Thread.currentThread().isInterrupted());
//        System.out.println("Main Thread is interrupted? " + Thread.interrupted());
        try {
            TimeUnit.MINUTES.sleep(1);
        } catch (InterruptedException e) {
            System.out.println("I will be interrupted still.");
        }

思考:打开注释和关闭注释的区别?

如何关闭一个线程
守护线程

若JVM中没有一个非守护线程时,JVM的进行会退出。
守护线程具备自动结束生命周期的特性,经常用于执行一些后台工作,因此有时它也被称为后台线程。

//伪代码如下
Thread thread = new Thread();
thread.setDaemon(true);
thread.start()
上一篇 下一篇

猜你喜欢

热点阅读