文档章节

Java线程(1)-读Thread类源码

Aunu
 Aunu
发布于 2017/09/17 13:41
字数 6520
阅读 32
收藏 0

Java线程(1)

[TOC]

前些天就看完了那本大名鼎鼎的《Java并发实战》,然而回头想想其实只是硬啃,工作中用到多线程的时候并不多,没有实战直接啃书,啃书也没有敲几行代码,没什么收获是必然。 所以,自己先梳理一遍。

线程概述

进程-process

说线程得先说一下进程,因为线程是运行在进程上下文中的逻辑控制流,一个进程可以有一个或多个线程(至少要有一个)。

而进程的定义为一个执行中的程序实例,进程有独立的逻辑控制流和私有的地址空间。

逻辑控制流:程序计数器值的序列 程序计数器的值是指令的地址,所以线程说白了就是一系列指令,并且线程间共享进程内的地址空间。

为了追求并发,提高资源利用率和加快执行时间,进程发展到多进程,但多进程之间的地址空间相互都不可见,数据难以共享(可以通过IPC机制,但很慢),所以在进程之下抽象出线程的概念(另外I/O多路复用的并发后面再谈)。

线程-thread

线程就是运行在进程上下文中的逻辑流。

线程拥有自己的上下文(context),包含唯一的线程ID, 栈,栈指针,程序计数器、通用目的寄存器和条件码,并且共享进程内的地址空间(代码,数据、堆、共享库、文件)。

线程是调度的抽象。Java中将线程的执行和执行对象抽象开来,JDK包中执行的有Thread类,Executor框架,可执行目标有Runaable,Callable。

jdk1.8 API

Thread类

Class Thread


All Implemented Interfaces:
Runnable
Direct Known Subclasses:
ForkJoinWorkerThread


public class Thread implements Runnable {
  
}

API中Thread类注释中写道:

  • thread为程序中执行的线程,并且JVM允许程序并发的执行多线程。

  • 线程拥有优先级,高优先级的线程会优先于低优先级的线程。每个线程可以标记也可以不标记为守护线程。当线程中新建一个线程时,新线程的优先级于创建线程相同,当且紧当创建线程为守护线程时,新线程才会是守护线程。

  • JVM启动,通常会有一个非守护线程(通常特定类下的main方法),当调用Runtime类下的exit方法并且安全管理器已经允许退出操作,或所有非守护线程已经死亡,JVM才会不再执行线程。

  • 创建可执行的线程

    • 继承Thread类,重写run方法。
    • 实现Runnable接口,实现run方法,作为参数传给创建的Thread实例。
  • 每个线程都有一个名称,用于定义/标识目的,多个线程可能有相同的名称。如果创建时未指定名称,JVM会生成一个名称。

综上:

  • Thread类实现了Runnable接口。
  • 每个线程有优先级,有名称。
  • 创建线程的本质:实现/重写Runnable接口的run方法,然后作为参数传给Thread对象启动。

所以Thread类暂时停一下,转去看Runnable接口

Runable接口

Runable故名思意,可执行的。

All Known Subinterfaces:
RunnableFuture<V>, RunnableScheduledFuture<V>
All Known Implementing Classes:
AsyncBoxView.ChildState, ForkJoinWorkerThread, FutureTask, RenderableImageProducer, SwingWorker, Thread, TimerTask

子接口和实现类,除了Thread现在还一窍不知。暂时不要纠结,继续下面


@FunctionalInterface
public interface Runnable
The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread. The class must define a method of no arguments called run.
任何想要被线程执行的实例需要实现Runnable接口,并且必须定义一个无参的run方法。

This interface is designed to provide a common protocol for objects that wish to execute code while they are active. For example, Runnable is implemented by class Thread. Being active simply means that a thread has been started and has not yet been stopped.
该接口旨在为active时执行代码的对象提供一个通用的协议。例如,Runnable由Thread类实现。active简单理解为,一个线程已经start,但未stop。


In addition, Runnable provides the means for a class to be active while not subclassing Thread. A class that implements Runnable can run without subclassing Thread by instantiating a Thread instance and passing itself in as the target. In most cases, the Runnable interface should be used if you are only planning to override the run() method and no other Thread methods. This is important because classes should not be subclassed unless the programmer intends on modifying or enhancing the fundamental behavior of the class.


继承Thread类,对于一个类而言限定了其基本行为,设计上非常不可取(多用组合 少用继承)。
所以Runable接口的意义就是在于:实现该接口的类可以称为被执行的类,不必因继承Thread类而被过分限定。

松耦合。

所以推荐的做法是
public class ThreadTest implements Runnable{


    @Override
    public void run(){
        System.out.println("run....");
    }

}

而不是
public class ThreadTest extends Thread{


    public void run(){
        System.out.println("run....");
    }

}

源代码:

@FunctionalInterface //函数式接口声明,编译器会检查接口定义是否合法。
public interface Runnable {
    /**
     * When an object implementing interface Runnable is used
     * to create a thread, starting the thread causes the object's
     * run method to be called in that separately executing
     * thread.
     * 当使用实现接口Runnable的对象来创建线程时,启动线程将导致该对象的run方法在该单独执行的线程中被调用。
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

jdk1.5时,在java.util.concurrent包下新增了一个接口:Callable<V>。 Callable,名字上就是可调用的,可赎回的。 Callable<V>与Runable接口在定义上就很明显,多了一个V--返回结果类型,若无法返回结果则返回异常。Callable<V>由Excutor类执行,这个等说完Thread类再提。

继续转到Thread类上面。

Thread类图

Thread类的方法有很多,这里简单分了一下(源码在读,并无多少经验,错误请纠正)

注:方法入参被省略,Deprecated为已经过期方法,没必要再用。

线程执行相关

  • yield()
  • sleep()
  • init()
  • start()
  • run()
  • exit()
  • stop()-Deprecated
  • interrupt()
  • destroy-Deprecated
  • isAlive()
  • suspend()-Deprecated
  • resume()-Deprecated
  • join()
  • holdsLock()

线程信息相关

  • setPriority()
  • getPriority()
  • setName()
  • getName()
  • setDaemon()
  • isDaemon()
  • getContextClassLoader()
  • setContextClassLoader()
  • getStackTrace()
  • getAllStackTraces()
  • checkAccess()
  • isCCLOverridden()
  • auditSubclass()
  • dumpThreads()
  • getThreads()
  • getId()
  • getState()
  • setDefaultUncaughtExceptionHandler()
  • getDefaultUncaughtExceptionHandler()
  • getUncaughtExceptionHandler()
  • setUncaughtExceptionHandler()
  • dispatchUncaughtException()
  • processQueue()

线程信息相关

  • nextThreadNum()
  • nextThreadID()
  • currentThread()
  • toString

线程组信息

  • getThreadGroup()
  • activeCount()
  • enumerate()
  • countStackFrames()-Deprecated

还没算内部静态类,已经晕的差不多。我个人就是每次打开都吓死人,看都不想看。 硬着头皮看下去,嗯,先来属性。


     /* Make sure registerNatives is the first thing <clinit> does. */
     //确定registerNatives()首先被<clinit>。
     //<clinit>-class initialization类初始化方法,包含静态属性和静态语句块。
    private static native void registerNatives();
    static {
        registerNatives();
    }

    private volatile String name; //线程名称-volatile属性,线程可见非原子。
    private int            priority; //线程优先级
    private Thread         threadQ;
    private long           eetop;

    /* Whether or not to single_step this thread. */
    private boolean     single_step; //是否单步?

    /* Whether or not the thread is a daemon thread. */
    private boolean     daemon = false;//是否为保护线程

    /* JVM state */
    private boolean     stillborn = false; //jvm状态

    /* What will be run. */
    private Runnable target;//被执行的目标,是Runnable

    /* The group of this thread */
    private ThreadGroup group;//当前线程组

    /* The context ClassLoader for this thread */
    private ClassLoader contextClassLoader;//当前线程上下文类加载器

    /* The inherited AccessControlContext of this thread */
    private AccessControlContext inheritedAccessControlContext;//继承的访问控制上下文

      /* For autonumbering anonymous threads. */
    private static int threadInitNumber;//线程初始化数,为匿名线程自动编号
    
    
    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
     //当前线程有关的ThreadLocal值,该map由ThreadLocal类保存
    ThreadLocal.ThreadLocalMap threadLocals = null;

    /*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.
     */
     //可继承的ThreadLocal
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    
    /*
     * Thread ID
     */
    private long tid;//线程id

    /* For generating thread ID */
    private static long threadSeqNumber;//生成的线程id

    /* Java thread status for tools,
     * initialized to indicate thread 'not yet started'
     */

    private volatile int threadStatus = 0;//java线程状态,初始化后表明线程还未启动

    /**
     * The argument supplied to the current call to
     * java.util.concurrent.locks.LockSupport.park.
     * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker
     * Accessed using java.util.concurrent.locks.LockSupport.getBlocker
     */
     //该参数支持当前线程调用java.util.concurrent.locks.LockSupport.park。
     //由(private) java.util.concurrent.locks.LockSupport.setBlocker设置
     //通过java.util.concurrent.locks.LockSupport.getBlocker访问
    volatile Object parkBlocker;

    /* The object in which this thread is blocked in an interruptible I/O
     * operation, if any.  The blocker's interrupt method should be invoked
     * after setting this thread's interrupt status.
     */
    //该对象在可中断的I/O操作中阻塞的线程中。 
    //在设置此线程的中断状态后,应调用阻塞程序的中断方法。
    private volatile Interruptible blocker;
    private final Object blockerLock = new Object();

    /* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code
     */
     //设置blocker字段,通过java.nio代码的sun.misc.SharedSecrets调用
    void blockedOn(Interruptible b) {
        synchronized (blockerLock) {
            blocker = b;
        }
    }
    
    /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;//最低优先级

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;//默认优先级

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;//最高优先级

属性就说明了线程首先拥有名称、id,jvm为后续线程生成的id,是否为守护线程,执行目标,线程状态,jvm状态,所属线程组,优先级(最该10,默认5,最低1). 所以线程那些getter/setter方法可以略过。重要的是事关线程执行的几个方法。 首先先新建一个Thread类,即新建一个线程。

 public void newThread(){
       Thread thread = new Thread();
 }

调用的构造器是:

/**
 * Allocates a new Thread object. This constructor has the same
 * effect as #Thread(ThreadGroup,Runnable,String)
 * Thread(null, null, gname), where gname is a newly generated
 * name. Automatically generated names are of the form
 *  "Thread-"+n, where n is an integer.
 */
  public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
 }

其中会调用init()方法,即初始化线程。 之前已经讲了各项属性,那初始化必要的属性呢?

  • 线程执行环境是什么
  • 如何确定线程唯一
  • 线程执行目标是什么?
  • .....

  /**
     * Initializes a Thread with the current AccessControlContext.
     * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext,boolean)
     */
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }

init(ThreadGroup, Runnable, String,long)进一步调用#init(ThreadGroup,Runnable,String,long,AccessControlContext,boolean)


    /**
     * Initializes a Thread.
     *
     * @param g the Thread group  //线程组
     * @param target the object whose run() method gets called //对象的run()方法被作为执行目标
     * @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.  //stackSize  表示新建线程的栈深,0表示忽略这个参数
     * @param acc the AccessControlContext to inherit, or        //AccessControlContext或者被继承,或者AccessController.getContext()
     *            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) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;

        Thread parent = currentThread();//当前线程为父级线程
        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 doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();//如果安全管理器拿不到,就获取父线程的线程组
            }
        }

        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
           //不管threadgroup是否明确传入,需要检查是否有权限访问此线程组
        g.checkAccess();

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


        //线程组中nUnstartedThreads+1,未启动的线程不会添加到线程组中,以便可以被收集。
        //但必须计数避免其守护线程组被销毁。
        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);
        
        //可继承的ThreadLocals值,从父级获取
        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 */
        //线程id
        tid = nextThreadID();
    }

回头一看,发现初始化线程要的东西还很多。基本就是那些属性了...瘫 继承父级线程的多个属性,线程组加了安全检查、控制访问等等,要注意的是调用了g.addUnstarted()这个方法。

这个方法表明初始化的线程,本身是unStarted。这里就要讲线程的状态了。Thread类中定义了一个枚举State,表示线程的状态。

State枚举


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.
         */
         //可运行的,在JVM中处于运行中,但可能等待来自操作系统的其他资源,如处理器。
        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.
         */
         //等待中......
         //由于调用Object.wait()未设置时间、Thread.join()未设置时间、LockSupport.park()。
         //等待中的线程意味中等待其他线程完成一个特定的动作。
         //需要被唤醒
        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>
         */
         //限时等待中......
         //指定了等待时间。
         //触发方法-Thread.sleep()、Object.wait()、Thread.join()、LockSupport.parkNanos()、LockSupport.parkUntil()
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
         //go die
         //线程完成了执行任务。
        TERMINATED;
    }

线程有五个状态:

  • NEW new Thread()初始化后,unstarted
  • Runable 可运行的
  • BLOCKED 已阻塞,等待进入同步块/方法
  • WAITING 等待中...
  • TIMED_WAITING 限时等待中......
  • TERMINATED 终结 go die

线程状态转换

Thread状态转换

上图为线程状态转换图。

start()

NEW-->RUNNABLE, 调用start()方法 RUNNABLE-->TERMINATED run方法执行完毕


    /**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     使线程开始执行,JVM调用该线程的run()方法
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     两个线程并发的执行:当前线程和执行run()方法的线程
     * It is never legal to start a thread more than once.
     多次启动一个线程是不合法的
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *一个线程执行完成后不可能会再一次重启
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
     //start()方法加了内置锁
    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".
         */
        if (threadStatus != 0)// 0相当于NEW状态
            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. */
         通知线程组,该线程将要启动,所以该线程要加入近线程组的列表中,nUnstartedThreads-1
        group.add(this);

        boolean started = false;
        try {
            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 */
            }
        }
    }

    //本地方法启动线程----阿阿阿阿,本地方法后面去看源码么....
    private native void start0();


本地start0()方法源码如下,文件是openjdk-jdk8u-jdk8u\hotspot\src\share\vm\runtime\thread.cpp

void Thread::start(Thread* thread) {
  trace("start", thread);
  // Start is different from resume in that its safety is guaranteed by context or
  // being called from a Java method synchronized on the Thread object.
  //Start和重新启用不同,它的安全性由上下文保证,或者由Thread对象的上的同步方法调用
  if (!DisableStartThread) {
    if (thread->is_Java_thread()) {
      // Initialize the thread state to RUNNABLE before starting this thread.
      // Can not set it after the thread started because we do not know the
      // exact thread state at that time. It could be in MONITOR_WAIT or
      // in SLEEPING or some other state.
      //启动当前线程时,需要初始化线程状态到RUNNABLE
      //线程启动后无法设置,因为我们不知道那时的线程状态。
      //可能是MONITOR_WAIT或SLEEPING或某些其他状态。
      java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),
                                          java_lang_Thread::RUNNABLE);
    }
    os::start_thread(thread);
  }
}

“java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),java_lang_Thread::RUNNABLE);”代码应该是c++ lambda表达式,设置当前线程状态为RUNNABLE,然后启动线程。

测试

public class ThreadTest  {
   @Test
   public void newThread() throws InterruptedException {
       Thread thread = new Thread();
       //线程是否启动
       System.out.println(thread.isAlive());//false
       System.out.println(thread.getState());//NEW
             
             
       thread.start();
       
       System.out.println(thread.isAlive());//true
       
       System.out.println(thread.getState());//RUNNABLE
       
       thread.sleep(1000L);
       
       System.out.println(thread.getState());//TERMINATED
       System.out.println(thread.isAlive());//false
   }
}

测试结果表明,new Thread()线程的确是未启动的NEW状态,start()后线程启动-状态为RUNNABLE. isAlive()方法也是本地方法,测试当前方法是否活着--指已经启动且未死亡.

现在线程已经启动了,那该执行目标,目标是实现Runable中的run()方法。

   /**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

上面测试代码中什么都没有就是因为new Thread()一没重写run()方法,二没传入Runnable对象,所以target为空,不会执行什么。把测试方法改一下。

public class ThreadTest  {


    @Test
    public void runnableTest()  {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable:run~~~~miao~");
            }
        });

        thread.start();
    }
    
}

//Runnable:run~~~~miao~

或者写成


public class SubThread extends Thread{
    public void run(){
        System.out.println("SubThread:run~~~~miao~~~");
    }
    
    
    @Test
    public void subThreadTest() {


        SubThread subThread = new SubThread();
        subThread.start();
    }
}

//SubThread:run~~~~miao~~~


run()方法和start()方法有什么区别么? 本身没有毛线关系,或者说都是线程不可缺的部分??? 咳,start()方法是启动线程的,线程启动后交给VM去执行run()方法中的代码。run()方法代表需要执行的目标,执行完线程就go die。

public class ThreadTest  {


    @Test
    public void runTest()  {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable:run~~~~miao~");//Runnable:run~~~~miao~
            System.out.println("currentThread1:"+Thread.currentThread().getName());//currentThread1:main
            }
        },"1");//命名为1

        System.out.println(thread.isAlive());//false
        System.out.println(thread.getState());//NEW
        thread.run();
        System.out.println(thread.isAlive());//false
        System.out.println(thread.getState());//NEW
        System.out.println("currentThread:"+Thread.currentThread().getName());//currentThread:main
    }
    
    
//线程未启动,执行Thread.run()的是main线程-当前线程。
    
    @Test
    public void startTest()  {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable:run~~~~miao~");//Runnable:run~~~~miao~
            System.out.println("currentThread1:"+Thread.currentThread().getName());//currentThread1:1
            }
        },"1");//命名为1

        System.out.println(thread.isAlive());//false
        System.out.println(thread.getState());//NEW
        thread.start();
        System.out.println(thread.isAlive());//true
        System.out.println(thread.getState());//RUNNABLE
        System.out.println("currentThread:"+Thread.currentThread().getName());//currentThread:main
    }
    
}

//线程1已经启动,执行Thread.run()的是1线程。

sleep()

RUNABLE-->TIMED_WATING sleep入参为毫秒数,时间过后会自动醒来进入RUNABLE状态,中间过程且不释放任何锁。

/**
     * Causes the currently executing thread to sleep (temporarily cease
     * execution) for the specified number of milliseconds, subject to
     * the precision and accuracy of system timers and schedulers. The thread
     * does not lose ownership of any monitors.
     *sleep(long millis)导致当前正在执行的线程休眠(暂停执行)指定的毫秒数,
     时间取决于系统定时器和调度程序的精度和准确性。 
     线程不会丢失任何monitor-j监控器的所有权。
     * @param  millis
     *         the length of time to sleep in milliseconds//休眠的时间长度,以毫秒计
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     //millis为负数,则抛出IllegalArgumentException异常
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     //任何线程中断当前线程抛出InterruptedException。当该异常抛出时,线程的中断状态被清除
     */
    public static native void sleep(long millis) throws InterruptedException;

    /*
     * @param  millis
     *         the length of time to sleep in milliseconds//休眠的时间长度,以毫秒计
     *
     * @param  nanos
     *         {@code 0-999999} additional nanoseconds to sleep//添加的纳秒,毫微秒
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative, or the value of
     *          {@code nanos} is not in the range {@code 0-999999}
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          interrupted status of the current thread is
     *          cleared when this exception is thrown.
     */
    public static void sleep(long millis, int nanos)
    throws InterruptedException {
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {//999999 <nanos>= 500000 超过半毫秒,毫秒+1
            millis++;
        }

        sleep(millis);
    }


测试


    public synchronized void  miao(){
        System.out.println(Thread.currentThread().getName() + ":miao~");
        try {
            Thread.currentThread().sleep(10000l);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    @Test
    public void sleepTest()  {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                miao();
            }
        },"thread");


        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("I: "+i);
                    if(i == 5){
                        miao();
                    }
                }

            }
        },"thread1");




        thread1.start();
        thread.start();
        
    }
    

运行结果为

thread:miao~
I: 0
I: 1
I: 2
I: 3
I: 4
I: 5
//或者
I: 0
thread:miao~
I: 1
I: 2
I: 3
I: 4
I: 5

两个线程并未指定优先级,故优先级继承父级的都为5. 线程启动后,thread先执行miao(),获得锁,打印语句后休眠了10000毫秒,休眠中让出了cpu资源给thread1,但thread1打印到5之后想去去调用miao()方法,然而锁被thread持有,无法调用.

join()

等待线程死亡,不传参数或者毫秒为0意味着永远等待。 循环判断线程是否存活,存活则调用wait()方法。 当线程终止时,调用this.notifyAll方法。建议应用程序不要在线程实例上使用wait,notify或notifyAll。

//RUNABLE-->TIMED_WATING-->TERMINATED
public final void join() throws InterruptedException {
        join(0);
}

//RUNABLE-->TIMED_WATING-->TERMINATED
public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

Object.wait()



//一直等待,直到另一个线程调用此对象的notify()方法或notifyAll()
//RUNABLE-->WATING 
public final void wait() throws InterruptedException {
        wait(0);
}

//限时等待,时间过去或者等另一个线程调用此对象的notify()方法或notifyAll()  
//RUNABLE-->TIMED_WATING  
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
    throw new IllegalArgumentException("timeout value is negative");
}

if (nanos < 0 || nanos > 999999) {
    throw new IllegalArgumentException(
                        "nanosecond timeout value out of range");
}

if (nanos > 0) {
    timeout++;
}

wait(timeout);
}

public final native void wait(long timeout) throws InterruptedException;

当前线程必须拥有该对象的监视器-锁,wait()后当前线程释放锁,并且进入WATING/TIMED_WATING状态,直到被唤醒/等待时间过去,才会重新获得锁并且进入可执行状态。

Object.notify()

    public final native void notify();

本地final方法,唤醒正在等待锁的单个线程。如果多个线程正在等待这个对象,选择其中一个唤醒。选择是任意的。线程通过调用wait()等待对象的监视器。

直到当前的线程放弃对象上的锁,否则唤醒的线程无法继续。

Object.notifyAll()

    public final native void notifyAll();

本地final方法,唤醒正在等待锁的所有线程。但是只有一个线程会获取到对象的锁,所有会产生竞争。

测试


public class ThreadTest  {

    public void waitTest(Queue<Integer>  lock) throws InterruptedException {
        synchronized (lock){
            while (lock.isEmpty()){
                System.out.println("isEmpty wait....");
                lock.wait();
            }
            System.out.println("remove....");
            lock.remove();


        }



    }

    public void notifyTest(Queue<Integer>  lock) throws InterruptedException {
        synchronized (lock){
            while (lock.isEmpty()){
                lock.notifyAll();
                Integer integer = new Random().nextInt();
                lock.add(integer);
                System.out.println("notify...."+ integer);
            }



        }


    }

    @Test
    public void  waitAndNotifyTest(){
        Queue<Integer> lock = new LinkedList<>();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {

                while (true){
                    try {
                        waitTest(lock);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        });


        Thread other = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    try {
                        notifyTest(lock);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        });
        thread.start();


        other.start();
    }


}


输出结果:

isEmpty wait....
notify....-822726143
remove....
isEmpty wait....
notify....1976737136
remove....
isEmpty wait....
notify....-28970457
remove....
isEmpty wait....
notify....1895823085
remove....
isEmpty wait....
notify....-1214156559
remove....

interrupt()

interrupt() 中断线程 除非当前线程正在中断自身(始终允许),否则将调用此线程的checkAccess方法,这可能会导致抛出SecurityException异常。 如果当前线程因调用Object类的wait()方法,join(),sleep()方法。线程中断的状态将会被清除,并且抛出InterruptedException.

如果当前线程在InterruptibleChannel上被阻塞在I/O操作中,那么通道将被关闭,线程的中断状态将被设置,抛出ClosedByInterruptException。

如果该线程在Selector中被阻塞,则线程的中断状态将被设置,并且它将从选择操作立即返回,可能具有非零值,就好像Selector.wakeup()被调用。

如果以前的条件都不成立,则该线程的中断状态将被设置。

中断不存在的线程没有任何影响。

interrupted() 测试当前线程是否中断,该方法可以清除线程的中断状态

isInterrupted() 测试此线程是否已中断。线程的中断状态不受此方法的影响。

yeild()

/**
A hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore this hint.
//对调度程序的一个暗示,即当前线程愿意放弃当前使用的处理器。调度程序可以自由地忽略这个提示。
Yield is a heuristic attempt to improve relative progression between threads that would otherwise over-utilise a CPU. Its use should be combined with detailed profiling and benchmarking to ensure that it actually has the desired effect.
//Yield是一种启发式尝试,以改善将过度利用CPU的线程之间的相对进度。其使用应与详细的分析和基准相结合,以确保其具有预期的效果。
It is rarely appropriate to use this method. It may be useful for debugging or testing purposes, where it may help to reproduce bugs due to race conditions. It may also be useful when designing concurrency control constructs such as the ones in the java.util.concurrent.locks package.
//很少使用这种方法.可能对调试或测试有用,可能有助于根据竞争条件重现错误.在设计并发控制结构时,例如java.util.concurrent.locks包中的并发控制结构也可能有用。

*/
    public static native void yield();

yield,放弃。当前线程可以让出占用的处理器,但可以被调度器忽略。也就是说不一定会成功。 但也可能成功,从而改善线程之间的过度竞争。 经测试,线程少的情况下用和不用基本没什么太大的区别,线程数增加后会出现各个线程交错运行的情况,改善了因竞争导致单个线程等待过长的问题。

holdsLock()

    public static native boolean holdsLock(Object obj);

如果当前的线程对指定的对象拥有监视器锁的时候,调用该方法返回true。 该方法旨在允许程序断言当前线程已经保存指定的锁。

  assert Thread.holdsLock(obj);

碎碎念

差不多读完了Thread类的代码,对Thread的属性和方法大概有了些了解。 其实也没有以前想的那么难 后面就是写代码了,回头还要再看一遍《并发编程实战》。

Refenrence

  • 《深入理解计算机系统第三版》
  • 《深入理解Java虚拟机第二版》
  • 《Java并发编程实战》
  • 《clean code》

© 著作权归作者所有

上一篇: Java基础知识一
Aunu
粉丝 1
博文 11
码字总数 18394
作品 0
广州
程序员
私信 提问
ThreadLocal源码分析

阅读原文请访问我的博客 BrightLoong's Blog 一. 简介 提醒篇幅较大需耐心。 简介来自ThreadLocal类注释 ThreadLocal类提供了线程局部 (thread-local) 变量。这些变量与普通变量不同,每个线...

BrightLoong
2018/05/28
0
0
JUC锁框架——ReadWriteLock

ReadWriteLock简单介绍 ReadWriteLock管理一组锁,一个是只读的锁,一个是写锁。读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的。相对于互斥锁而言,ReadWriteLoc允许更高的并发...

长头发-dawn
2018/09/17
0
0
ThreadLocal和InheritableThreadLocal深入分析

  通过ThreadLocal和InheritableThreadLocal,我们能够很方便的设计出线程安全的类。JDK底层是如何做到的呢?ThreadLocal和InheritableThreadLocal有什么区别呢与联系呢?为什么有了Threa...

良辰美景TT
2018/08/14
0
0
理解Java ThreadLocal

ThreadLocal如果单纯从名字上来看像是“本地线程"这么个意思,只能说这个名字起的确实不太好,很容易让人产生误解,ThreadLocalVariable(线程本地变量)应该是个更好的名字。我们先看一下官...

目翟
2013/08/05
0
0
ThreadLocal 类 的源码解析以及使用原理

1、原理图说明      首先看这一张图,我们可以看出,每一个Thread类中都存在一个属性 ThreadLocalMap 成员,该成员是一个map数据结构,map中是一个Entry的数组,存在entry实体,该实体包...

小勇DW3
2018/08/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

对集合的理解

开端 同事小G提了一点,Set都是无序的,但是我之前有看到过treeSet是有序的,就和他讨论了起来,还百度了一下,有序。然而他只是淡淡的说自己敲代码验证一下。 TreeSet 循环int类型 1~20,毫...

无极之岚
40分钟前
3
0
Kernel字符设备驱动框架

Linux设备分为三大类:字符设备,块设备和网络设备,这三种设备基于不同的设备框架。相较于块设备和网络设备,字符设备在kernel中是最简单的,也是唯一没有基于设备基础框架(device结构)的...

yepanl
44分钟前
3
0
Ajax

定义 Ajax是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术,用于创建动态网页 Ajax=Asynchronous Javascript And XML(异步的JavaScript和XML) 原理 XMLHttpRequest对象(异...

星闪海洋
昨天
3
0
Jenkins 中文本地化的重大进展

本文首发于:Jenkins 中文社区 我从2017年开始,参与 Jenkins 社区贡献。作为一名新成员,翻译可能是帮助社区项目最简单的方法。 本地化的优化通常是较小的改动,你无需了解项目完整的上下文...

Jenkins中文社区
昨天
4
0
Spring中如何使用设计模式

关于设计模式,如果使用得当,将会使我们的代码更加简洁,并且更具扩展性。本文主要讲解Spring中如何使用策略模式,工厂方法模式以及Builder模式。 1. 策略模式 关于策略模式的使用方式,在S...

爱宝贝丶
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部