前言:

这篇文章主要就什么是进程、什么是线程、线程的五个状态、线程的终止来展开讲解java多线程的知识点。

正文:

一、什么是进程?

    进程是系统进行资源分配和调度的基本单位,它是程序执行时的一个实例。程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行。

二、什么是线程?

   线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

三、进程和线程的关系

通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度。

四、线程的状态

我们可以通过打开java.lang.thread的源码里看到,线程定义的6个状态

1.New: 尚未启动的线程的线程状态。

2.Runnable: 可运行线程的线程状态,等待CPU调度。

3.Blocked: 线程阻塞等待监视器锁定的线程状态。

4.Waiting:等待线程的线程状态。下列不带超时的方式:

Object.wait、Thread.join、LockSupport.park

5.Timed Waiting:具有指定等待时间的等待线程状态。下列带超时的方式

Thread.sleep、Object.wait、Thread.join、LockSupport.parkNanos、LockSupport.parkUntil

6. Terminated:线程终止的状态。线程正常完成执行或者出现异常。

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

这里我写个Demo,来看下状态的变换

 public static void main(String[] args) throws InterruptedException {
        //第一种状态切换 - 新建 -> 运行 -> 终止
        System.out.println("######第一种状态切换 - 新建 -> 运行 -> 终止############################");
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread1当前状态:"+Thread.currentThread().getState().toString());
                System.out.println("thread1 执行了");
            }
        });
        System.out.println("没调用start方法,thread1当前状态:"+thread1.getState().toString());
        thread1.start();
        Thread.sleep(2000L);//等待thread1执行结束,再看状态
        System.out.println("等待两秒,再看thread1当前状态:"+thread1.getState().toString());
        //thread1.start(); //TODO注意,线程终止之后,再进行调用,会抛出IllegalThreadStateException异常
}

 运行的结果打印:

######第一种状态切换 - 新建 -> 运行 -> 终止############################
没调用start方法,thread1当前状态:NEW
thread1当前状态:RUNNABLE
thread1 执行了
等待两秒,再看thread1当前状态:TERMINATED

其他的状态,可以编写一下试试,有的文章里会写在可运行状态前有种状态叫做就绪状态是Runnable,运行时状态是Running,但是如果你打印线程当前的运行状态其实是Runnable。

 四、线程的终止

1.不正确的终止方式

thread.stop方法终止线程,会导致线程不安全。通俗的说,即使你在run()方法的代码块里加上synchronized关键字,也无法保证原子性操作,因为stop会破会这个原子性,拦腰折断

public class StopThread extends Thread {
    private int i = 0, j = 0;

    @Override
    public void run() {
        synchronized (this) {
            //增加同步锁,确保线程安全
            ++i;
            try {
                //休眠10秒,模拟耗时操作
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ++j;
        }
    }

    public void print(){
        System.out.println("i="+i+"j="+j);
    }
public static void main(String[] args) throws InterruptedException {
        StopThread thread = new StopThread();
        thread.start();
        //休眠1秒,确保i变量自增成功
        Thread.sleep(1000);
        thread.stop();//错误的终止
        Thread.sleep(1000);
        System.out.println(thread.isAlive());
        while (thread.isAlive()){
            //确保线程已经终止
        }
        thread.print();
    }

 运行结果:

false
i=1j=0

我们可以明显看到,i和j的结果不一样,破坏了 synchronized关键字同步效果。

2.正确的终止方式

2.1调用thread.interrupt()方法就可以正确终止线程。把上面的例子改成interrupt来终止线程,i与j的结果就保持一致。
public static void main(String[] args) throws InterruptedException {
        StopThread thread = new StopThread();
        thread.start();
        //休眠1秒,确保i变量自增成功
        Thread.sleep(1000);
        hread.interrupt();//正确的终止
        Thread.sleep(1000);
        System.out.println(thread.isAlive());
        while (thread.isAlive()){
            //确保线程已经终止
        }
        thread.print();
    }

运行后的结果: 

java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at com.study.oa.study.StopThread.run(StopThread.java:13)
false
i=1j=1

 2.2 还可以用标志位来正确终止线程

public class Demo4 extends Thread{
    public volatile static boolean flag=true;
    public static void main(String[] args) throws InterruptedException {
       new Thread(() ->{
           try {
               while (flag){//判断是否运行
                   System.out.println("运行中");
                   Thread.sleep(1000L);
               }
           }catch (InterruptedException e){
               e.printStackTrace();
           }
       }).start();
       //3秒之后,将状态标志改为false,代表不继续运行
       Thread.sleep(3000L);
       flag=false;
        System.out.println("程序运行结束");

    }

}

参考内容:以上的内容来自个人总结于网易云课堂的学习。

总结:

线程的学习坑点有很多,大家一定要有耐心,因为想迈入高级java编程,多线程开发是无法避免的。我是阿达,一名喜欢分享知识的程序员,时不时的也会荒腔走板的聊一聊电影、电视剧、音乐、漫画,这里已经有172位小伙伴在等你们啦,感兴趣的就赶紧来点击关注我把,哪里有不明白或有不同观点的地方欢迎留言。