Java教程

【Java多线程 01】认识线程

本文主要是介绍【Java多线程 01】认识线程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、什么是线程

目前,基本上所有操作系统都支持多任务的执行,对计算机来说,每一个人物就是一个进程,而在每一个进程内部,都至少有一个线程正在运行。我们有时称线程是轻量级的进程。线程是程序执行的路径,每一个线程都拥有自己的局部变量表,程序计数器以及各自的生命周期。

 

二、线程的生命周期

线程的生命周期其实还是很好理解的,分为 New, Runnable, Running, Blocked, Terminated 五个阶段,包含了线程从创建、到运行、再到死亡的全过程。

线程生命周期
图1 线程的生命周期

 1. New 状态

当我们用关键字new创建一个Thread对象时,线程处于New状态。本质上,这只是一个普通的Java对象。当然,我们调用start()方法就可以进入Runnable状态。

2. Runnable 状态

进入 Runnable 状态后,线程加入线程池等待CPU的调度。执行了,但没有完全执行。由于存在Running状态,所以不会直接进入Blocked或者Terminated状态。严格来说,Runnable只能意外终止或者进入Running。

3. Running 状态

Runnable状态或者CPU调度后,进入Running状态,开始运行线程的执行单元。

初始状态转换状态原因
RunningRunnable

CPU调度器轮询要求线程放弃执行

主动调用yield

RunningBlocked

调用sleep/wait/join方法

进行某个阻塞的IO操作

获取某个同步锁资源

RunningTerminated调用stop或者JVM Crash

4. Blocked 状态

一个正在执行的线程在某些特殊情况下,如执行耗时的输入/输出操作时,会放弃CPU的使用权,进入阻塞状态。线程进入阻塞状态后,就不能进入排队队列。只有当引用阻塞的原因,被消除后,线程才可以进入就绪状态。

5. Terminated 状态

线程的run()方法正常执行完毕,线程抛出一个未捕获的异常或错误或者JVM崩溃,线程就进入死亡状态。一旦进入死亡状态,线程将不再拥有运行的资格,也不能转换为其他状态。

三、Java Thread类源码

1. 内部参数

public class Thread implements Runnable {
    // 我们忽略一些目前不太重要的参数
    
    // 线程名
    private volatile String name;
    // 优先级
    private int priority;

    // 是否是守护线程
    private boolean daemon = false;

    // 是否导入Runnable作为参数,如果target为空,就会执行run()方法,否则运行target
    private Runnable target;

    // 确定线程组
    private ThreadGroup group;

    // 类加载器,待补充
    private ClassLoader contextClassLoader;

    // 访问控制,待补充
    private AccessControlContext inheritedAccessControlContext;

    // 如果Thread没有定下名字,这个数字用来自动生成"Thread-1"这样子的名字。
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }


    /*
     * 线程栈的大小
     * The requested stack size for this thread, or 0 if the creator did
     * not specify a stack size.  It is up to the VM to do whatever it
     * likes with this number; some VMs will ignore it.
     */
    private final long stackSize;


    /*
     * 线程 ID
     */
    private final long tid;

    /* For generating thread ID */
    private static long threadSeqNumber;

    private static synchronized long nextThreadID() {
        return ++threadSeqNumber;
    }

    /*
     * Java thread status for tools, default indicates thread 'not yet started'
     */
    private volatile int threadStatus;

    ... 

}

2、创建线程

public class Thread implements Runnable {

    ...
    /* 这个是私有的构造函数,公开的构造函数很多都是选取其中部分参数 */
    private Thread(ThreadGroup g, Runnable target, String name,
                   long stackSize, AccessControlContext acc,
                   boolean inheritThreadLocals) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;
        
        // 确定父进程
        Thread parent = currentThread();
        // 获取SecurityManager
        SecurityManager security = System.getSecurityManager();
        // 线程池逻辑段
        if (g == null) {
            /* Determine if it's an applet or not */

            /* If there is a security manager, ask the security manager
               what to do. */
            if (security != null) {
                g = security.getThreadGroup();
            }

            /* If the security manager doesn't have a strong opinion
               on the matter, use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
        g.checkAccess();

        /*
         * Do we have the required permissions?
         */
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(
                        SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        g.addUnstarted();

        this.group = g;
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        this.target = target;
        setPriority(priority);
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        this.tid = nextThreadID();
    }

    ... 

}

3、start() 方法

public class Thread implements Runnable{

    ...


    public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        // 如果线程状态不为NEW, 报错
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        // 放入线程池
        group.add(this);
        // 标记,还未开始
        boolean started = false;
        try {
            // C/C++写的本地方法,真正开始运行逻辑
            start0();
            // 运行成功
            started = true;
        } finally {
            try {
                if (!started) {
                    // 线程启动失败
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    ...

}

 

四、创建线程的方法

总共有两种方法创建线程。一种是创建一个Thread类的子类,这个子类应当重写run()方法。

       class PrimeThread extends Thread {
           long minPrime;
           PrimeThread(long minPrime) {
               this.minPrime = minPrime;
           }
  
           public void run() {
               // compute primes larger than minPrime
                . . .
           }
       }

运行方法:

       PrimeThread p = new PrimeThread(143);
       p.start();

另一种则是实现Runnable接口,并将其作为参数传递给Thread类。

       class PrimeRun implements Runnable {
           long minPrime;
           PrimeRun(long minPrime) {
               this.minPrime = minPrime;
           }
  
           public void run() {
               // compute primes larger than minPrime
                . . .
           }
       }

运行方法:

       PrimeRun p = new PrimeRun(143);
       new Thread(p).start();

 

这篇关于【Java多线程 01】认识线程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!