JAVA 多线程并发编程学习笔记 一 Thread 类

Thread 的各种状态

(1) NEW

/**
 * Thread state for a thread which has not yet started.
 */
   NEW -- 新建状态
   当创建线程后,没有进行start() 操作之前

(2) RUNNABLE

/**
 * 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 -- 就绪状态,执行状态
  执行start()之后,处于就绪状态;当被CPU调度后处于运行状态

(3) BLOCKED

/**
* 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 -- 阻塞状态
  在进行同步操作,等待锁时会进入该状态(wait, await)
  可通过唤醒notify,single 进入RUNNABLE状态

(4) WAITING

/**
 * 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 -- 等待状态
  一般执行 wait() other.join()等不加时间参数的方法,
  等待的线程需要被唤醒才能继续运行

(5) TIMED_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 -- 时间等待状态
   执行sleep(long )  wait(long )  other.join(long )等
   时间到了会自动唤醒

(6) TERMINATED

/**
 * Thread state for a terminated thread.
 * The thread has completed execution.
 */
   TERMINATED -- 终止状态
   执行stop() destroy() 或者 run执行结束

关系图如下
这里写图片描述

Thread 类

(1) 成员变量

//记录线程是否开始,在start()方法中会进行判断,因为一个线程不能同时开启多次
boolean started = false;

private volatile String name;  //线程名称

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

private Runnable target;  //传入的Runnable 对象

private ThreadGroup group;  //线程所在线程组

//线程中ThreadLocalMap 对象
ThreadLocal.ThreadLocalMap threadLocals = null;

private long stackSize;  //栈大小

private long tid;  //线程id

//用来计算的线程id, 其实 id = ++threadseqNumber;
private static long threadSeqNumber;   

private volatile int threadStatus = 0;  //线程状态

private int priority;  //线程优先级 以及 给的优先级的值

/**
* 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;

(2) 构造方法

公有构造方法:

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

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

    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);
    }

Runnable target : 开发者实现的Runnable 对象,start后 会调用target的run方法
String name : 开发者定义的线程名称, 通过Thread.currentThread().getName() 获取
ThreadGroup group : 创建的线程所在线程组,用来对线程进行管理,通过myThread.getThreadGroup().getName()获得,默认main线程
long stackSize : 线程开辟的栈大小

以上8种重载的构造方法中进行如下初始化:

    private void init(ThreadGroup g, Runnable target, 
                                    String name, long stackSize) {
        Thread parent = currentThread();//获得当前线程
        //如果开发没有设置线程组,那么设置为默认的,测试过为main 线程
        if (g == null) {
            g = parent.getThreadGroup();
        }

        g.addUnstarted();               //线程组未启动的线程数量+1
        this.group = g;

        this.target = target;           //添加runnable
         //先将优先级和是否是守护线程定义为线程组的,
         //因为开发者可能不通过setPriority setDaemon 方法设置
        this.priority = parent.getPriority();
        this.daemon = parent.isDaemon();
        setName(name);           //设置线程名称

        init2(parent);

        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;    //线程栈大小
        tid = nextThreadID();  //线程id
    }

    private void init2(Thread parent) {
        this.contextClassLoader = parent.getContextClassLoader();
        this.inheritedAccessControlContext
                                  =AccessController.getContext();
        //查看当前线程中是否已经存在ThreadLocal,如果有了,
        //则将之前使用的ThreadLocal 信息存到本Thread中
        if (parent.inheritableThreadLocals != null) {
            this.inheritableThreadLocals = 
                    ThreadLocal.createInheritedMap(
                    parent.inheritableThreadLocals);              
        }
    }

私有构造方法:整体和init() 方法一致,但未发现使用在哪里

    /** @hide */
    // Android-added: Private constructor - used by the runtime.
    Thread(ThreadGroup group, String name, int priority, 
                                                boolean daemon) {
        this.group = group;
        this.group.addUnstarted();          
        // Must be tolerant of threads without a name.
        if (name == null) {
            name = "Thread-" + nextThreadNum();
        }
        this.name = name;

        this.priority = priority;
        this.daemon = daemon;
        init2(currentThread());
        tid = nextThreadID();
    }

构造方法是给Thread 的成员变量group、target、priority、daemon、name、ThreadLocalMap、stackSize、tid 赋值的。

(3) 常用方法

start

    /**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * start 方法存在的原因是:jvm 调用该线程的run 方法
    */
    public synchronized void start() {
        /**
         * A zero status value corresponds to state "NEW".
         * 如果不是new 状态,或者已经start了,则抛出异常
         */
        // Android-changed: throw if 'started' is true
        if (threadStatus != 0 || started)              
            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 该线程准备start了,所以添加到group 的集合中,
         * 并且group没有start的线程数量递减
         */
        group.add(this);

        started = false;
        try {
            //开启线程,传递给底层执行
            nativeCreate(this, stackSize, daemon); 
            started = true;
        } finally {
            try {
                if (!started) {
                //start 失败会通知group remove 该线程,
                //并group 没有start的线程数量加1                    
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    //native 方法,调用JNI创建线程传递的是当前线程实例,栈大小,是否守护线程
    //所以设置守护线程必须在start()方法之前!!!
    private native static void nativeCreate(Thread t, long stackSize, 
                                                    boolean daemon);
  1. 判断是否start 多次
  2. 添加的group 中
  3. 通知JVM 开启线程
  4. 开启失败抛出异常

run
Thread 类本身实现Runnable 接口,所以会重写Run方法

    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
  1. 通过run() 调用,可理解为线程没开启,在线程所在的线程中执行的run方法
  2. 通过start() 调用,在一个线程的执行方法,执行开发implements Runnable 中的run 方法

注意点:调用start() 和 run() 区别 以及 次数
相同: 调用start 和 run ,都会执行Thread 中的run 方法
不同: start() 真正开启一个线程,并且只能调一次,
否则会java.lang.IllegalThreadStateException 异常;内部通过判断线程状态,!= 0 时抛出异常;run 仅仅是执行一下run 方法,不会创建一个线程,并且可以调用多次。


sleep
字面意思睡觉,不释放当前占用的资源,休眠结束后继续执行;会让出CPU 执行其他任务,睡眠结束后,会再次执行该线程

   public static void sleep(long millis) throws InterruptedException {
       Thread.sleep(millis, 0);
   }

    @FastNative
    private static native void sleep(Object lock, long millis, 
                              int nanos) throws InterruptedException;

    public static void sleep(long millis, int nanos)
    throws InterruptedException {
        //如果设置的毫秒,纳秒小于0 或者 纳秒 > 999999 表示设置失败,
        //抛出IllegalArgumentException 不合法参数异常
        if (millis < 0) {
          throw new IllegalArgumentException("millis < 0: " + millis);
        }
        if (nanos < 0) {
          throw new IllegalArgumentException("nanos < 0: " + nanos);
        }
        if (nanos > 999999) {
          throw new IllegalArgumentException("nanos > 999999: " 
                                                         + nanos);
        }

        //设置为0 时,没有意义,如果线程中断则抛出中断异常,否则直接返回
        if (millis == 0 && nanos == 0) {
            // ...but we still have to handle being interrupted.
            if (Thread.interrupted()) {
              throw new InterruptedException();
            }
            return;
        }

        long start = System.nanoTime();   //获得纳秒级时间
        long duration = (millis * NANOS_PER_MILLI) + nanos;//睡眠时长

        Object lock = currentThread().lock;

      // Wait may return early, so loop until sleep duration passes
      // 通过计算,判断睡眠时长时候过了,否则一直等待。
      //并通过sleep 告诉JVM 该线程处于睡眠状态,run 方法不执行
        synchronized (lock) {
            while (true) {
                sleep(lock, millis, nanos);

                long now = System.nanoTime();
                long elapsed = now - start;

                if (elapsed >= duration) {
                    break;
                }

                duration -= elapsed;
                start = now;
                millis = duration / NANOS_PER_MILLI;
                nanos = (int) (duration % NANOS_PER_MILLI);
            }
        }
    }
  1. 判断输入时间是否异常
  2. 通过死循环向JVM 更新发送睡眠时间,直到到时退出循环

join
字面意思参加,一个线程中调用other.join(),将等待other执行完后才继续本线程
join方法必须在线程start方法调用之后调用才有意义

    public final void join() throws InterruptedException {
        join(0);
    }

    public final void join(long millis, int nanos)
    throws InterruptedException {
        synchronized(lock) {
        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)) {
            millis++;
        }

        join(millis);
        }
    }   

    public final void join(long millis) throws InterruptedException {
        synchronized(lock) {
        long base = System.currentTimeMillis();
        long now = 0;

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

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

那么在A 线程中调用B.join(), 是如何将A线程停止的呢?
从源码中可以看到,join() 方法中,有wait() 方法。所以在A中,B.join,相当于A 调用了wait() 方法
通过isAlive()来判断B线程是否还在运行,或者通过delay 来判断时间是否到了,如果不满足,wait方法会让A线程进入阻塞状态,并且会释放线程占有的锁,并交出CPU执行权限;否则退出join 方法,A线程可重新被调度使用。


yield
字面意思放弃,让出CPU资源,让其他线程使用CPU, 由于不能控制CPU的资源分配,所以可能出现thread让出CPU资源后,又立刻重新调用了。
不会进入阻塞状态 而是进入就绪状态runnable,再次等待被CPU调度

    public static native void yield();

interrupt()
中断

    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();
        //看当前线程是否进入阻塞
        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                nativeInterrupt();
                b.interrupt(this);
                return;
            }
        }
        //调用native 方法
        nativeInterrupt();
    }

    private native void nativeInterrupt();

isInterrupted() 判断线程是否中断

 public native boolean isInterrupted();

直接使用interrupt()是无法终止的,可以用isInterrupted() 一起使用,来退出循环。


stop 停止
destroy 销毁

This method is inherently unsafe.  Stopping a thread with
Thread.stop causes it to unlock all of the monitors that it
has locked (as a natural consequence of the unchecked
<code>ThreadDeath</code> exception propagating up the stack)

过时,线程不安全的,不能释放所有的锁
这个线程本质是不安全的,停止使用该方法的原因是:不能释放所有监视锁


other
setName 设置线程名
getName 获取线程名
setPriority 设置线程优先级
getPriority 获取线程优先级
setDaemon 设置守护线程
isDaemon 判断是否是守护线程

Thread.currentThread() 获得当前线程实例
public static native Thread currentThread();


以上就是Thread 类中主要的内容,有错误就麻烦大家提出来了。
Thanks
~看到新问题会继续补充

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值