Android知识点整理3:线程

目录

1、简介

2、进程和线程对比

3、线程的状态:线程从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态及死亡状态。

4、线程启动的几种方式

5、 线程start方法到底做了什么,怎么回调到run方法

6、sleep和wait的区别


1、简介

线程的概念:CPU调度的最小单元

2、进程和线程对比

(1)、进程是资源分配最小单位,线程是程序执行的最小单位

(2)、进程有自己独立的地址空间,线程没有独立的地址空间

(3)、CPU切换一个线程比切换进程花费小,线程比进程开销小

(4)、进程对资源保护要求高,线程资源保护不高。

3、线程的状态:线程从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态及死亡状态。

新建状态(New):new一个Thread() 对象

就绪状态(Runnable): 新建一个线程不会自动运行,而是需要start开启后,进入就绪状态,然后在获取cpu选中才能进如运行状态,执行run方法

运行状态(Running):当线程处于准备就绪状态,并获得cpu时间资源后,才进入了运行状态

阻塞状态(Blocked):当线程因为各种原因,比如sleep操作,io被阻止、想获取一个被锁资源等原因导致线程被阻塞

死亡状态(Dead):run方法自然结束后或者因为某个未捕获异常而导致线程终止

图如下:(图来源于网上)


 

4、线程启动的几种方式

根据jdk官方api,有两种方式https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/Thread.html

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.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.

一种是继承Thread,复写run方法,然后start

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

另外一种,实现Runnable接口,再Thread有参数构造,start

class PrimeRun implements Runnable {
         long minPrime;
         PrimeRun(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:

         PrimeRun p = new PrimeRun(143);
         new Thread(p).start();
     

我看网上很多文章说还有FutureTask 啥的方式,这个其实就是Runnable接口的变种方式。可以看到源码:

public class FutureTask<V> implements RunnableFuture<V> 
public interface RunnableFuture<V> extends Runnable, Future<V>

5、 线程start方法到底做了什么,怎么回调到run方法

我们可以通过源码可以看到 start回调用native层nativeCreate方法

start线程的方法,代码如下

 public synchronized void start() {
        if (started)
            throw new IllegalThreadStateException();
        started = false;
        try {
            nativeCreate(this, stackSize, daemon);
            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 */
            }
        }
    }

那么怎么在开启后回调到run方法呢?先看下nativeCreate方法定义

// Android-changed: Use Android specific nativeCreate() method to create/start thread.
    // The upstream native method start0() only takes a reference to this object and so must obtain
    // the stack size and daemon status directly from the field whereas Android supplies the values
    // explicitly on the method call.
    // private native void start0();
    private native static void nativeCreate(Thread t, long stackSize, boolean daemon);

看注释我们可以看到有个start0() 方法,旧版本是调用start0()这个方法,由于android-30 lang 下面Thread.java 对应的c代码不好找,我退而求其次,去找了jdk7里面Thread.cpp 源码

http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/share/native/java/lang/Thread.c

还有个网址:http://androidxref.com/

这个类里面有定义start0() 这个方法

#include "jni.h"

#include "jvm.h"


#include "java_lang_Thread.h"


#define THD "Ljava/lang/Thread;"

#define OBJ "Ljava/lang/Object;"

#define STE "Ljava/lang/StackTraceElement;"


#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))


static JNINativeMethod methods[] = {

    {"start0",           "()V",        (void *)&JVM_StartThread},

    {"stop0",            "(" OBJ ")V", (void *)&JVM_StopThread},

    {"isAlive",          "()Z",        (void *)&JVM_IsThreadAlive},

    {"suspend0",         "()V",        (void *)&JVM_SuspendThread},

    {"resume0",          "()V",        (void *)&JVM_ResumeThread},

    {"setPriority0",     "(I)V",       (void *)&JVM_SetThreadPriority},

    {"yield",            "()V",        (void *)&JVM_Yield},

    {"sleep",            "(J)V",       (void *)&JVM_Sleep},

    {"currentThread",    "()" THD,     (void *)&JVM_CurrentThread},

    {"countStackFrames", "()I",        (void *)&JVM_CountStackFrames},

    {"interrupt0",       "()V",        (void *)&JVM_Interrupt},

    {"isInterrupted",    "(Z)Z",       (void *)&JVM_IsInterrupted},

    {"holdsLock",        "(" OBJ ")Z", (void *)&JVM_HoldsLock},

    {"getThreads",        "()[" THD,   (void *)&JVM_GetAllThreads},

    {"dumpThreads",      "([" THD ")[[" STE, (void *)&JVM_DumpThreads},

};


#undef THD

#undef OBJ

#undef STE


JNIEXPORT void JNICALL

Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls)

{

    (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));

}

从这个cpp文件可以找到 start0()的定义

 {"start0",           "()V",        (void *)&JVM_StartThread},

可以看这篇文章的直接通过Hotspot JVM 源码找到

https://blog.csdn.net/GuiRongGe/article/details/105920893

最后会c调用java的 Thread 的 run方法

template(run_method_name,                           "run")

我们直接看thread的 run方法做了什么

@Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

这个target是 Runnable实现类,所以会回调run方法执行操作

6、sleep和wait的区别

 sleep这个方法是在Thread这个类里面,wait则在Object类中

sleep方法的过程中,线程不会释放对象锁,wait方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用 notify方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。

wait来说使用之前要获取到锁的存在,所以必须放在同步代码,或者同步中进行执行 但是 sleep来说可以放在任何的地方执行 。

sleep()方法导致了程序暂停执行指定的时间,让出 cpu 该其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态。wait则需要被唤醒

sleep需要捕获异常 ,wait notify 等不需要这些。

猜你喜欢

转载自blog.csdn.net/wuqiqi1992/article/details/107878581