java.lang.Thread源码阅读笔记

1. 线程简介

A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.

一个thread是程序中一个线程的执行。JVM允许应用在并发执行时使用多线程

Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. Each thread may or may not also be marked as a daemon.

每个线程都有自己的优先级。优先级高的执行时会优先于优先级低的线程。每个线程都有可能是守护线程。

When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, and is a daemon thread if and only if the creating thread is a daemon.

当在一些正在运行的线程中创建了新的Thread对象时,这个新线程的初始的优先级和创建它的线程的优先级相同。并且当且仅当创建它的线程是守护线程时它才是守护线程。

源码如下: “` this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); “`

When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named main of some designated class). The Java Virtual Machine continues to execute threads until either of the following occurs:

当JVM启动时,一定存在一个单线程的非守护线程的方法(在一些设计的类中通常是叫作main的这个方法)。JVM会继续执行这个方法直到以下几种情况出现:

  • The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.

    Runtime类的exit方法被调用,并且安全管理员允许exit操作发生

  • All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.

    所有非守护线程死亡。因从调用返回到run方法死亡,或者因超出run方法而抛出异常而死亡

2. 创建线程的方法


There are two ways to create a new thread of execution. One is to
declare a class to be a subclass of Thread. This
subclass should override the run method of class
Thread. An instance of the subclass can then be allocated and started.


有两种创建线程的方式。一种是声明一个类,该类继承于Thread。并且要覆写run方法。接着便可以分配或启动这个子类的实例了。

代码示例如下:

“`
class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}

      public void run() {
          // compute primes larger than minPrime
     }
 }

“`


The following code would then create a thread and start it running:


下面的代码会创建一个线程,并启动线程


PrimeThread p = new PrimeThread(143);
p.start();


The other way to create a thread is to declare a class that
implements the Runnable interface. That class then
implements the run method. An instance of the class can then be allocated, passed as an argument when creating Thread, and started.


另一种创建线程的方式是:声明一个类,实现Runnable接口。然后这个类实现run方法。然后这个类的实例便可被分配,当创建Thread时传值过去,便可以启动该线程了。

        class PrimeRun implements Runnable {
          long minPrime;
          PrimeRun(long minPrime) {
             this.minPrime = minPrime;
          }

          public void run() {
              // compute primes larger than minPrime
          }
      }
      PrimeRun p = new PrimeRun(143);
      new Thread(p).start();

以第二种方式创建线程完整代码示例:

public class PrimeRun implements Runnable {
    long minPrime;

    public PrimeRun (long minPrime){
        this.minPrime = minPrime;
    }

    @Override
    public void run(){
        long i = minPrime;

            if (isPrime(i))
                System.out.println(i);
    }

    public boolean isPrime(long num){
        for (int i = 2; i < num - 1; i++){
            if (num % i == 0) return false;
        }
        return true;
    }

    public static void main(String[] args) {
        PrimeRun p = new PrimeRun(143);
        new Thread(p).start();
    }
}


Every thread has a name for identification purposes. More than
one thread may have the same name. If a name is not specified when
a thread is created, a new name is generated for it.


每个线程都有一个作为其身份标识的名字。多个线程可能会重名。如果创建线程时未指定名称,则会为其生成一个新名称。


Unless otherwise noted, passing a {@code null} argument to a constructor
or method in this class will cause a {@link NullPointerException} to be
thrown.


除非另有说明,否则的话,如果在这个类中向构造函数或方法传递一个null参数,将会抛出link NullPointerException异常。

3. 常用方法:

1. yield()


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
{@link java.util.concurrent.locks} package.


想要恰当的使用这个方法很难。它可能对调试或测试很有用,因为它可能有助于重现由于竞争状况下产生的错误。它也可能有助于设计并发控制结构,比如包中的java.util.concurrent.locks

2. sleep()

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.

 根据系统定时器和调度器的精确性和准确性的限制,使当前执行的线程sleep(暂时停止执行)特定的毫秒。不过这个线程不会失去对监视器的所有权。

 *
 * @param  millis
 *         the length of time to sleep in milliseconds

 sleep的时间长短(毫秒)

 *
 * @throws  IllegalArgumentException
 *          if the value of {@code millis} is negative

 如果{@code 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后,interrupted status(被中断的状态)将会被清除

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

      如果{@code millis}为负数,或者{@code nanos}的值不在{@code 0-999999}这个区间内,则抛出IllegalArgumentException异常

      *

    • @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)) {
            millis++;
        }

        sleep(millis);
    }
3. start()

Causes this thread to begin execution; the Java Virtual Machine
calls the run method of this thread.


使该线程开始执行。JVM调用此线程的run方法


The result is that two threads are running concurrently:
the current thread (which returns from the call to the
start method) and the other thread (which executes its
run method).


调用该方法的结果是两个线程同时执行:从调用返回到start方法的当前线程,和执行它的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()
     */
    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.

         主线程或VM创建或设置的的组线程"system"不会调用这个方法。未来新添加到这个方法的新功能都要加入到VM中。

         *
         * A zero status value corresponds to state "NEW".
           0对应着"NEW"状态
         */
        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 */
            }
        }
    }
4. run()

If this thread was constructed using a separate Runnable run object, then that Runnable object’s run method is called; otherwise, this method does nothing and returns.

如果这个线程是使用单独的Runnable运行对象的,那么调用Runnable对象的run方法;否则,这个方法什么也不做直接返回。

Subclasses of Thread should override this method.

Thread的子类需要重写这个方法

      * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

——————————————————————————-

以上为依据,下面为本人的总结:

1. 线程

  • 每个线程都有自己的优先级
  • 被创建出来的新的线程的优先级和创造它的线程的优先级相同
  • 什么时候才会退出主线程?
    • 调用Runtimeexit()方法(如果允许的话)
    • 所有非守护线程死亡。因从调用返回到run方法死亡,或者因超出run方法而抛出异常而死亡

2. 怎样创建线程?

  • 两种方法:
    1. 继承Thread类。覆写run方法
    2. 实现Runnable接口。然后这个类实现run方法
  • 比较
    • 继承自Thread类不适合资源共享,因为Java不支持多继承
    • 实现Runnable接口可以实现资源共享
      1. 适合多个相同的程序代码的线程去处理同一个资源
      2. 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。

3.yield()方法有什么作用?

  • 孔融让梨(让出该线程所拥有的处理器)。不过,这梨不一定让得出去,也许人家那小孩不想吃,所以意味着,这梨可能还在孔融手里。

4. sleep()方法有什么作用?

  • 使线程休眠一段时间,但并不失去监控器的拥有权(其实就是不失去锁monitor)
  • 有两个重载的方法,一个可以传入毫秒为参数,另一个可以传入毫秒和纳秒。
  • 可能会抛出异常:
    • 如果当前线程被中断,会抛出InterruptedException异常,并且抛出异常后,interrupted status(被中断的状态)将会被清除
    • 如果传入的参数不正确,会抛出IllegalArgumentException异常。

5. start()与run()方法的区别

我是这样理解的,如有误请尽管指出
- start()启动线程可以实现多线程并行,run()只是一个普通的方法
- 用start()方法启动线程,可以实现多线程真正并行,因为无需等待run()线程体执行完毕,而是可以继续执行后面的代码。线程被start()启动后处于就绪状态,等得到CPU运行时间片后才会执行run()
- 用run()方法启动线程,程序还是要等到其执行完毕才能继续后面的代码。
- 举个栗子

public class Example implements Runnable {
    public static void main(String[] args) {
        Example p = new Example();

        new Thread(p).start();
        System.out.println("i hate u");
    }

    @Override
    public void run() {
        sayLoudly();
    }

    static void sayLoudly(){
        System.out.println("i love u");
    }
}

这段代码的执行结果是:

i hate u
i love u

如果将start()换成run(),则执行结果为:

i love u
i hate u

5. 如果多次启动一个线程会怎样?

会抛出IllegalThreadStateException异常
为什么不可以多次启动一个线程?
看图:
image

图源Stack Overflow

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值