zoukankan      html  css  js  c++  java
  • 并发学习第二篇——Thread

    一、类的声明

    public class Thread implements Runnable {
    }

    Thread本身实现了Runnable接口,Runnable是一个task,Thread是执行它的载体

    二、native方法

    以下native方法直接与操作系统接触了,看名字应该就懂意思

    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
          registerNatives();
    }
    
    public static native Thread currentThread();
    public static native void yield();
    public static native void sleep(long millis) throws InterruptedException;
    private native void start0();
    private native boolean isInterrupted(boolean ClearInterrupted);
    public final native boolean isAlive();
    public static native boolean holdsLock(Object obj);

    三、关键属性

    1、volatile关键字修饰的

    //volatile修饰的表明对所有线程可见
    private volatile String name;
    //线程状态值为0表示线程尚未started
    private volatile int threadStatus = 0;

    2、其他属性

    private boolean     daemon = false;
    //需要运行的Runnable对象
    private Runnable target;
    //持有的ThreadLocalMap对象
    ThreadLocal.ThreadLocalMap threadLocals = null;
    //线程id
    private long tid;
    //指定优先级时最小值
    public final static int MIN_PRIORITY = 1;
    //分派给线程的默认优先级值
    public final static int NORM_PRIORITY = 5;
    //线程可以指定的优先级的最大值
    public final static int MAX_PRIORITY = 10;

    四、构造方法

    构造方法之前,先看看init方法,因为所有的构造方法都调用了这个,这里忽略掉了非关键的一些代码逻辑

    init主要做初始化线程名(如果未指定会默认分配成"Thread-" + nextThreadNum())

    初始化待执行的target(一个Runnable)

    分配一个线程ID

    private void init(Runnable target, String name) {
         init(target, name);
    }
    private void init(Runnable target, String name) {
         if (name == null) {
             throw new NullPointerException("name cannot be null");
         }
         this.name = name;
         //被创建的这个线程是当前线程的子线程
         Thread parent = currentThread();
         //被创建的这个线程默认拥有当前线程的daemon和priority属性
         this.daemon = parent.isDaemon();
         this.priority = parent.getPriority();
         this.target = target;
         //分配线程ID
         tid = nextThreadID();
    }

    以下构造方法也都舍弃了一些非关键参数和代码逻辑

    1、无参

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

    2、仅指定任务对象作为参数

    public Thread(Runnable target) {
        init(target, "Thread-" + nextThreadNum());
    }

    记笔记:当线程启动后,target的run()方法被调用,如果target==null,run()方法不做任何事情

    3、仅指定线程名作为参数

     public Thread(String name) {
         init(null,name);
    }

    4、指定任务对象和线程名

    public Thread(Runnable target, String name) {
         init(target, name);
    }

    记笔记:当线程启动时将调用target的run()方法,如果target==nul,将调用Thread的run()方法

    五、start()方法

    public synchronized void start() {
           if (threadStatus != 0)
                throw new IllegalThreadStateException();
            group.add(this);
            boolean started = false;
            try {
                start0();
                started = true;
            } finally {
                try {
                    if (!started) {
                        group.threadStartFailed(this);
                    }
                } catch (Throwable ignore) {
                  }
            }
        }
    
    private native void start0();

    这是一个synchronized方法,且判断了 threadStatus是否等于0,否则抛出异常 

    在try里面调用了start0(),这是一个native的方法,前面讲了在static块中会执行registerNatives(),注册本地方法

    这个时候JVM会执行真正的"创建线程","启动线程","回调线程run()方法"

    关于JVM里发生了什么,这位大师兄讲的很好,戳这里:https://www.cnblogs.com/xiaofuge/p/14040715.html

    另外划个重点:一个线程只能启动一次,连续调用两次start(),看看会发生什么!(代码手误造成的一次重大发现~~)

    六、线程状态枚举

    看看源码注释

        /**
         * A thread state.  A thread can be in one of the following states:
         * {#NEW}:A thread that has not yet started is in this state.
         *    
         * {#RUNNABLE}:A thread executing in the Java virtual machine is in this state.
         *     
         *{#BLOCKED}:A thread that is blocked waiting for a monitor lock is in this state.
         *     
         * {#WAITING}:A thread that is waiting indefinitely for another thread to
         *     perform a particular action is in this state.
         *     
         * {#TIMED_WAITING}:A thread that is waiting for another thread to perform an action
         *     for up to a specified waiting time is in this state.
         *    
         * { #TERMINATED}:A thread that has exited is in this state.
         * 
         * A thread can be in only one state at a given point in time.
         * These states are virtual machine states which do not reflect
         * any operating system thread states.
         */
        public enum State {
            /**
             * a thread which has not yet started.
    * 一个尚未启动的线程处于这个状态
    */ NEW, /** * 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, /**
    * 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 {Object.wait}.
    * 当线程被调用了Object.wait()方法后,正在等待获得一个监视器锁来进入或重入一个synchronized方法/块时的状态
    */ 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> * 意思是说:当调用wait(),未设置超时的join(),LockSupport.park()时 * <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 a上调用了a.wait(),然后等待其他线程在a上调用Object.notify()或notifyAll()
    */ 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>
    * 这个和WAITING状态类似,只是增加了等待时长
    */ TIMED_WAITING, /** * The thread has completed execution. */ TERMINATED; }

    需要特别注意的是:这个State和前面提到的threadStatus属性是相关联的,在VM.class中是这么对应的

    public static State toThreadState(int var0) {
            if ((var0 & 4) != 0) {
                return State.RUNNABLE;
            } else if ((var0 & 1024) != 0) {
                return State.BLOCKED;
            } else if ((var0 & 16) != 0) {
                return State.WAITING;
            } else if ((var0 & 32) != 0) {
                return State.TIMED_WAITING;
            } else if ((var0 & 2) != 0) {
                return State.TERMINATED;
            } else {
                return (var0 & 1) == 0 ? State.NEW : State.RUNNABLE;
            }
        }

    而threadStatus的值的更改,不是在java代码中做到的,而是在JVM中做的

    七、其他重要方法

    1、sleep(网上有个说法叫"抱锁入睡"很形象)

        /**
         * 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.
         */
        public static native void sleep(long millis) throws InterruptedException;

    sleep时只按指定毫秒时间休眠,不释放锁

    2、join

    /**
         * Waits at most millis milliseconds for this thread to die. 
    * A timeout of
    0 means to wait forever. * * This implementation uses a loop of {this.wait} calls conditioned on {this.isAlive}.
    * As a thread terminates the {
    this.notifyAll} method is invoked.
    * It is recommended that applications not use
    wait,notify,or notifyAll on Thread instances. */ 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; } } }

    翻译下上面注释:等待最多mills毫秒,直到this thread死亡,0意味着一直等待

    实现方式是在while(isAlive())条件下循环调用wait()

    这个地方说实话,头几次自己琢磨没看懂,有点绕,跟了几次论坛的讨论帖才大体明白:

    上伪代码:

    //这里用run代替start,为了方便理解
    threadA.run(){
       ...;
       //join是synchronized的,这里需要获取threadB的对象锁
       //对象锁之前讲,实际上就像有一个BlockingQueue,尝试获取锁的线程都在里面排队等待
       synchronized threadB.join(){
          ...;
          while(threadB.isAlive()){
    //注意,这里是Object.wait()的调用,表示调用这句代码的线程(A)进入等待,而不是B
    //threadB只要仍然存活,threadB就调用wait()
    //这里插播一个,wait会使得当前线程(就是A)释放锁,就是说threadA会释放开头获取到的threadB的对象锁
    //然后threadA进入等待,直到B死亡时调用B.notifyAll,来wakeup threadA
    threadB.wait(); } } }

    最后这句:当线程terminated时会调用notifyAll(),这个也是在JVM中执行的

    也就是,当threadB执行结束,jvm会自动唤醒阻塞在threadB对象上的线程,让他们继续执行

    八、遗弃的方法

    stop(),destory(),suspend(),resume()

    这些方法对正在运行的线程侵入(干扰)过大,容易造成无法预期的后果,抛弃之

    最后来个辨析:为什么wait(),notify(),notifyAll()设计成Object类的方法,而不是Thread独有的

    几个角度

    1、锁是很通用的需求,java提供的锁是对象级的而不是线程级的,

    每个对象都可以有锁状态(对象头MarkWord中)因此理应属于对象的方法

    2、wait和notify都是对对象的锁进行的操作

    3、从观察者和被观察者的角度讲,对象是被观察者,线程是观察者,发生状态变化的一方(对象)理应去

    通知(notify,notifyAll)观察的人(线程);否则假设notify由观察者调用,他又怎么知道什么时候调用呢,

    如果观察者有一批,又怎么保证同时去notify呢

    4、由3考虑到观察者模式,以及一对多的关系中应该是"多"记录"一"的标识,这里因为有个队列的原因,是反的,

    对象要记下正在等待获取锁的线程

  • 相关阅读:
    双线性过滤
    textureView
    cubemap
    selfshadow
    cbuffer padding
    异常
    Python深浅拷贝
    数据类型分类
    集合类型内置方法
    字典数据类型内置方法
  • 原文地址:https://www.cnblogs.com/yb38156/p/14434514.html
Copyright © 2011-2022 走看看