jdk源码学习笔记---Thread
2017-08-06 19:39
591 查看
初衷
刚接触java不到2礼拜的小白试图通过阅读jdk的源码来学习java。如有理解或表达不对的地方,欢迎各位大佬指正,谢谢。0. 线程概述
线程是一个程序的多个执行路径,执行调度的单位,依托于进程存在。线程不仅可以共享进程的内存,而且还拥有一个属于自己的内存空间,这段内存空间也叫做线程栈,是在建立线程时由系统分配的,主要用来保存线程内部所使用的数据,如线程执行函数中所定义的变量。**注意:**Java中的多线程是一种抢占机制而不是分时机制。抢占机制指的是有多个线程处于可运行状态,但是只允许一个线程在运行,他们通过竞争的方式抢占CPU。
1. 线程的状态
在jdk1.8的Thread类中,定义了一个变量来存储当前线程的状态。private volatile int threadStatus = 0;
**注意:**volatile关键字修饰的变量具有弱同步的性质(线程访问volatile修饰的变量拿到的值是修改后的值),但volatile修饰的变量不具有原子性(volatile的变量只能保证可见性和有序性。可见性就是当多个线程访问一个变量时,其中一个线程修改了这个变量的值之后,其他线程能够立即拿到修改后的值,也就是说修改变量的值时不会经过cache,而是直接写入内存当中。而所谓的有序性就是程序执行的顺序是按照代码的顺序来执行的,也就是说屏蔽了jvm对指令的重排序)。
线程的状态主要分为以下几种状态:
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; }
新生状态(New): 当一个线程的实例被创建即使用new关键字和Thread类或其子类创建一个线程对象后,此时该线程处于新生(new)状态,处于新生状态的线程有自己的内存空间,但该线程并没有运行,此时线程还不是活着的(not alive);
就绪状态(Runnable): 通过调用线程实例的start()方法来启动线程使线程进入就绪状态(runnable);处于就绪状态的线程已经具备了运行条件,但还没有被分配到CPU即不一定会被立即执行,此时处于线程就绪队列,等待系统为其分配CPCU,等待状态并不是执行状态; 此时线程是活着的(alive);
运行状态(Running): 一旦获取CPU(被JVM选中),线程就进入运行(running)状态,线程的run()方法才开始被执行;在运行状态的线程执行自己的run()方法(target或者重写的run方法)中的操作,直到调用其他的方法而终止、或者等待某种资源而阻塞、或者完成任务而死亡;如果在给定的时间片内没有执行结束,就会被系统给换下来回到线程的等待状态;此时线程是活着的(alive);
阻塞状态(Blocked):
通过调用join()、sleep()、wait()或者资源被暂用使线程处于阻塞(blocked)状态;处于Blocking状态的线程仍然是活着的(alive)
死亡状态(Dead):
当一个线程的run()方法运行完毕或被中断或被异常退出,该线程到达死亡(dead)状态。此时可能仍然存在一个该Thread的实例对象,当该Thready已经不可能在被作为一个可被独立执行的线程对待了,线程的独立的call stack已经被dissolved。一旦某一线程进入Dead状态,他就再也不能进入一个独立线程的生命周期了。对于一个处于Dead状态的线程调用start()方法,会出现一个运行期(runtime exception)的异常;处于Dead状态的线程不是活着的(not alive)。
2. 线程的创建
当实例一个新的Thread对象时,辣么多的构造函数重载版本其实内部调用的是一个私有的init方法来初始化一些数据,例如target、优先级、threadid、栈空间的大小、线程组等。public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0< fd09 /span>); } public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } Thread(Runnable target, AccessControlContext acc) { init(null, target, "Thread-" + nextThreadNum(), 0, acc, false); } 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); } //init private void init(ThreadGroup g, Runnable target, String name, long stackSize) { init(g, target, name, stackSize, null, true); } //init core 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; //拿到当前执行的线程的线程对象,也就是调用start方法的线程。 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. */ g.checkAccess(); /* * Do we have the required permissions? */ if (security != null) { if (isCCLOverridden(getClass())) { security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } } //更新未开始的线程的计数 g.addUnstarted(); //设置是否为守护线程和线程的优先级(1-10) 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 */ tid = nextThreadID(); }
3. 线程的启动
外部想要启动一个线程是会调用start方法,start方法的启动过程是先检查线程状态是否为NEW,然后将自己添加到自己所属的线程组当中,然后调用native的start0方法,当抢到CPU的时间片后,jvm会调用这个线程的run方法。public synchronized void start() { 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 { 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();
4. 线程方法
想要自定义线程的方法体有两种途径,一种是继承Thread类然后重写run方法;另一种是实现Runable接口,然后再实例化Thread时将实现了Runable接口的对象传进去。@Override public void run() { //如果没有传Runable接口的对象那么将什么都不做,想要做点什么的话就要就乖乖重写run方法 if (target != null) { target.run(); } }
5. 各种控制
5.1 join
thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。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()) { //这里用的object的wait方法,也就是说这个线程必须是锁的持有者,然后暂时失去锁,当wait方法返回后又拿到锁。这就是为什么wait要在synchronized块中调用 wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
5.2 checkAccess
这货用来检查当前运行的线程有没有足够的权限来修改这个线程。主要用在对线程的状态进行控制时。public final void checkAccess() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkAccess(this); } } //SecurityManager.checkAccess public void checkAccess(Thread t) { if (t == null) { throw new NullPointerException("thread can't be null"); } if (t.getThreadGroup() == rootGroup) { checkPermission(SecurityConstants.MODIFY_THREAD_PERMISSION); } else { // just return } } //SecurityManager.checkPermission public void checkPermission(Permission perm) { java.security.AccessController.checkPermission(perm); }
5.3 yield
让出CPU的使用权,给其他线程执行机会、让同等优先权的线程运行(但并不保证当前线程会被JVM再次调度、使该线程重新进入Running状态),如果没有同等优先权的线程,那么yield()方法将不会起作用。public static native void yield();
5.4 sleep(静态)
当前线程睡眠/millis的时间(millis指定睡眠时间是其最小的不执行时间,因为sleep(millis)休眠到达后,无法保证会被JVM立即调度);sleep()是一个静态方法(static method) ,所以他不会停止其他的线程也处于休眠状态;线程sleep()时不会失去拥有的对象锁。作用:保持对象锁,让出CPU,调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留一定的时间给其他线程执行的机会;
public static void sleep(long millis, int nanos) throws InterruptedException { if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } //nanos表示纳秒 if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } if (nanos >= 500000 || (nanos != 0 && millis == 0)) { millis++; } sleep(millis); } public static native void sleep(long millis) throws InterruptedException;
5.5 getStackTrace
这个方法用来拿到该线程的栈轨迹信息,如果该线程还没有开始,或者还没有被调度,或者线程已经被终止(总的来说就是不是Alive状态),那么将会返回一个length为0的StackTraceElement[]。否则StackTraceElement[]中的第一个元素存放的是这个线程的栈中最近方法被调用的信息,最后一个元素存放这个线程的栈中最早方法被调用的信息。private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; private native static StackTraceElement[][] dumpThreads(Thread[] threads); public StackTraceElement[] getStackTrace() { if (this != Thread.currentThread()) { // check for getStackTrace permission SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission( SecurityConstants.GET_STACK_TRACE_PERMISSION); } // optimization so we do not call into the vm for threads that // have not yet started or have terminated if (!isAlive()) { return EMPTY_STACK_TRACE; } //new Thread[]{this}实际上是传递的一个只有一个元素的数组,而这个元素就是this(即这个线程) StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this}); //StackTraceElement[][]此时只有1行n列或者为null StackTraceElement[] stackTrace = stackTraceArray[0]; // a thread that was alive during the previous isAlive call may have // since terminated, therefore not having a stacktrace. if (stackTrace == null) { stackTrace = EMPTY_STACK_TRACE; } return stackTrace; } else { // Don't need JVM help for current thread return (new Exception()).getStackTrace(); } }
相关文章推荐
- CAFFE源码学习笔记之五-internal_thread
- jdk1.8源码学习笔记
- JAVA源码笔记(jdk 1.7.0_75)--Thread-详细版本
- JDK源码学习笔记——HashMap
- JDK源码学习笔记——LinkedHashMap
- CAFFE源码学习笔记之五-internal_thread
- CAFFE源码学习笔记之五-internal_thread
- JDK源码学习笔记——String
- jdk源码学习笔记---ArrayList
- CAFFE源码学习笔记之五-internal_thread
- JAVA源码笔记(jdk 1.7.0_75)--Thread-精简版本
- CAFFE源码学习笔记之五-internal_thread
- CAFFE源码学习笔记之五-internal_thread
- 基于JDK1.8的LinkedList源码学习笔记
- JDK8源码学习笔记之一:ArrayList
- jdk源码学习笔记--LinkedList
- CAFFE源码学习笔记之五-internal_thread
- JDK1.6 源码学习笔记(二)
- CAFFE源码学习笔记之五-internal_thread
- 安装卸载jdk学习笔记-CentOs下(源码、rpm安装)