Java多线程(1)——基本概念

一、基本概念

进程(process):程序的运行实例。进程与程序之间的关系就好比播放中的视频与对应的视频文件。进程是程序向操作系统申请资源(如内存空间和文件句柄)的基本单位。
线程(thread):进程中可独立执行的最小单位。一个进程可以包含多个线程,同一个进程中的所有线程共享该进程中的资源。Java平台中的一个线程就是一个对象。
任务(task):线程所要完成的计算。
串行(sequential):顺序逐一完成。
并发(concurrent):同一时间段交替完成。
并行(parallel):同一时刻开始完成。更为严格的并发。

二、线程的创建启动运行

Java中创建一个线程就是创建一个java.lang.Thread类的实例。线程的任务处理逻辑可以在Thread类的run实例方法中实现。它由虚拟机在运行相应线程时直接调用,而不是由应用代码调用。

Thread类的start方法的作用是启动相应的线程。启动一个线程的实质是请求虚拟机运行相应的线程,而这个线程具体何时能够运行是由线程调度器(scheduler)决定的。因此,start方法调用结束并不意味线程已经开始运行,这个线程可能稍后才被运行,甚至可能永远不会被运行。

线程的run方法执行结束,则相应的线程运行结束。线程的start方法只能调用一次,即线程属于一次性用品。

//Thread两个常用构造器
public class Thread implements Runnable {
    public Thread() {
        init(null,null,"Thread-"+nextThreadNum(),0);
    }

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

    /**
     * Initializes a Thread.
     *
     * @param g the Thread group
     * @param target the object whose run() method gets called
     * @param name the name of the new Thread
     * @param stackSize the desired stack size for the new thread, or
     *        zero to indicate that this parameter is to be ignored.
     * @param acc the AccessControlContext to inherit, or
     *            AccessController.getContext() if null
     * @param inheritThreadLocals if {@code true}, inherit initial values for
     *            inheritable thread-locals from the constructing thread
     */
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        //...
    }
}

虚拟机为每个线程分配调用栈(callstack)所需的内存空间,Java平台中的每个线程可能还有一个内核线程与之对应,因此,创建线程对象比创建其他类型的对象的成本要高一些。

三、线程属性

属性 类型 用途 备注
编号ID long 标识不同的线程。 某个编号的线程运行结束后,该编号可能被后续创建的线程使用。编号的唯一性只在Java虚拟机的一次运行有效。因此该属性的值不适合用作某种唯一标识(如主键)
名称Name String 面向人的属性,用于区分不同线程。默认为Thread-ID 设置线程的名称属性有助于代码调试和问题定位
线程类别Daemon boolean 是否为守护线程。默认与父线程相同 该属性必须在相应线程启动之前设置。负责关键任务处理的线程不适宜设置为守护线程
优先级Priority int Java定义了1~10的10个优先级。默认值一般为5(普通优先级)。对于具体的一个线程而言,其优先级的默认值与其父线程的优先级值相等。 一般使用默认优先级即可。

按照线程是否会阻止Java虚拟机正常停止,我们可以将Java中的线程分为 守护线程(DaemonThread)用户线程(UserThread,也称非守护线程)
用户线程会阻止Java虚拟机的正常停止,即一个Java虚拟机只有在其所有用户线程都运行结束的情况下才能正常停止。
而守护线程则不会影响Java虚拟机的正常停止,即应用程序中有守护线程在运行也不影响Java虚拟机的正常停止。
因此,守护线程通常用于执行一些重要性不是很高的任务,例如用于监视其他线程的运行情况。

四、Thread类

方法 功能 备注
static Thread currentThread() 返回当前线程
void run() 实现线程的人物处理逻辑 一般情况下应用程序不应该调用
void start() 启动相应线程 只能被调用一次
void join() 等待相应线程运行结束 A调用B的join方法 A暂停直到B运行结束
static void yield() 当前线程主动放弃其对处理器的占用,可能导致当前线程被暂停 方法不可靠
static void sleep(long millis) 休眠指定时间

五、线程的生命周期

由于Java虚拟机创建的main线程(主线程)负责执行Java程序的入口方法main方法。

父线程和子线程之间的生命周期没有必然的联系。

  • NEW:已创建而未启动的线程处于该状态。由于一个线程实例只能够被启动一次,因此一个线程只可能有一次处于该状态。
  • RUNNABLE:该状态可以被看成一个复合状态。它包括两个子状态:READY和RUNNING。
    READY 表示处于该状态的线程可以被线程调度器进行调度而使之处于 RUNNING 状态。处于该状态的线程为活跃线程。
    RUNNING 表示处于该状态的线程正在运行,即相应线程对象的run方法所对应的指令正在由处理器执行。
  • BLOCKED:一个线程发起一个阻塞式I/O(BlockingI/O)操作后,或者申请一个由其他线程持有的独占资源(比如锁)时,相应的线程会处于该状态。处于该状态的线程并不会占用处理器资源。
  • WAITING:一个线程执行了某些特定方法之后就会处于这种等待其他线程执行另外一些特定操作的状态。如:Object.wait()Thread.join()LockSupport.park(Object)。能够使相应线程从 WAITING 变更为 RUNNABLE 的相应方法包括:Object.notify()/notifyAll()LockSupport.unpark(Object))
  • TIMED_WAITING:该状态和 WAITING 类似,差别在于处于该状态的线程并非无限制地等待其他线程执行特定操作,而是处于带有时间限制的等待状态。当其他线程没有在指定时间内执行该线程所期望的特定操作时,该线程的状态自动转换为 RUNNABLE。
  • TERMINATED: 已经执行结束的线程处于该状态。一个线程也只可能有 一次处于该状态。Thread.run()正常返回或者由于抛出异常而提前终止都会导致相应线程处于该状态。





参考资料:《Java 多线程编程实战指南(核心篇)》 黄文海 著

猜你喜欢

转载自www.cnblogs.com/JL916/p/12309733.html