Thread

概念

线程是并发执行的单位。它内部的参数,局部变量和唤醒的方法都有自己的调用堆。当一个应用打开的时候至少有一个线程在运行,它就是主线程,在主线程组中。运行时在系统线程组中保持它自己的线程。

有两种方式运行一个新线程。你可以实现一个Thread的子类,然后覆写它的run方法,或者可以创建一个Thread,然后将一个Runnable对象当参数传入。无论使用上述哪种方式,都需要使用start方法来运行这个新线程。

每个线程都有一个int型的参数即优先级,它决定了这个线程如何被系统调度。新的线程继承父进程的优先级。一个线程可以使用setPriority(int)方法设定优先级。

源码分析

这次我准备从Thread调用方式入手,通常来说有两种调用方式,上文中也有提到。接下来我煮个��:

  1. class MyThread extends Thread {
    @Override
    public void run() {
    super.run();
    ......
    }
    }
    MyThread myThread = new MyThread();
    myThread.start();

    1. Thread thread = new Thread(new Runnable() {
      @Override
      public void run() {
      .....
      }
      });
      thread.start();

第一种就是构造一个Thread的子类然后覆写run方法,第二种是直接将Runnable当参数传入,并覆写Runnable里面的run方法。推荐使用第二种方式,更简洁。

现在进入到构造函数中

public Thread() {
create(null, null, null, 0);
}
public Thread(Runnable runnable) {
create(null, runnable, null, 0);
}

我们会发现构造函数非常多,抽取出两个我们用到频率比较高的,如上��
他们同时进入了一个叫create的方法,如下��

private void create(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {
Thread currentThread = Thread.currentThread();
if (group == null) {
group = currentThread.getThreadGroup();
}
if (group.isDestroyed()) {
throw new IllegalThreadStateException("Group already destroyed");
}
this.group = group;
synchronized (Thread.class) {
id = ++Thread.count;
}
if (threadName == null) {
this.name = "Thread-" + id;
} else {
this.name = threadName;
}
this.target = runnable;
this.stackSize = stackSize;
this.priority = currentThread.getPriority();
this.contextClassLoader = currentThread.contextClassLoader;
// Transfer over InheritableThreadLocals.
if (currentThread.inheritableValues != null) {
inheritableValues = new ThreadLocal.Values(currentThread.inheritableValues);
}
// add ourselves to our ThreadGroup of choice
this.group.addThread(this);
}

四个参数,线程组、runnable、线程名、堆大小。首先获取了当前所在线程currentThread,调用了一些native的东西

public static native Thread currentThread();

获取当前线程所在线程组:

group = currentThread.getThreadGroup();

public final ThreadGroup getThreadGroup() {
// TODO This should actually be done at native termination.
if (getState() == Thread.State.TERMINATED) {
return null;
} else {
return group;
}
}

如果当前线程状态不为终止,那么返回group。

然后设定线程id、线程名称、Runnable、堆大小、优先级等。线程id是诶一识别一个线程的东西,所以每个线程的id都是独一无二的,如果用户没有直接设定线程名称那么默认线程名为 Thread- + id 的格式,最后将线程推入线程组中。

当你创建了一个线程的时候,一定要用start()方法启动它,要不你创建它干嘛~在构造函数部分没发现什么激动人心的东西,于是我们来到了直接启动线程的start()方法。

public synchronized void start() {
checkNotStarted();
hasBeenStarted = true;
nativeCreate(this, stackSize, daemon);
}

想不到这么叼的方法居然只有三行啊哈哈哈��,让我们开始追根溯源

private void checkNotStarted() {
if (hasBeenStarted) {
throw new IllegalThreadStateException("Thread already started");
}
}

checkNotStarted()就是判断是这个线程是不是已经启动,如果你已经调用过一次start了,第234567…次调用start就会抛出线程已启动的异常的哟~

hasBeenStarted = true;将线程状态置为启动,nativeCreate(this, stackSize, daemon);调用了一个native方法:private native static void nativeCreate(Thread t, long stackSize, boolean daemon);,靠。。这就结束了。。。我一定是忘了什么。。。。。

老夫掐指一算在分析构造函数的时候有个方法结束了全篇,this.group.addThread(this);,对,就是它!将新建的线程扔到线程组就不管了,所以老夫猜测关于thread的调度之类的必在ThreadGroup中!

ThreadGroup构造方法:

/**
* Constructs a new {@code ThreadGroup} with the given name. The new {@code ThreadGroup}
* will be child of the {@code ThreadGroup} to which the calling thread belongs.
*
* @param name the name
* @see Thread#currentThread
*/
public ThreadGroup(String name) {
this(Thread.currentThread().getThreadGroup(), name);
}
/**
* Constructs a new {@code ThreadGroup} with the given name, as a child of the
* given {@code ThreadGroup}.
*
* @param parent the parent
* @param name the name
* @throws NullPointerException if {@code parent == null}
* @throws IllegalThreadStateException if {@code parent} has been
* destroyed already
*/
public ThreadGroup(ThreadGroup parent, String name) {
if (parent == null) {
throw new NullPointerException("parent == null");
}
this.name = name;
this.parent = parent;
if (parent != null) {
parent.add(this);
this.setMaxPriority(parent.getMaxPriority());
if (parent.isDaemon()) {
this.setDaemon(true);
}
}
}
/**
* Initialize the special "system" ThreadGroup. Was "main" in Harmony,
* but we have an additional group above that in Android.
*/
private ThreadGroup() {
this.name = "system";
this.parent = null;
}

也就是说如果你自己没有指定父线程组的话,那么就使用系统提供的ThreadGroup,系统已经默默为你创建了一个main thread 的时候就默默为你创建了一个 main ThreadGroup,如果你自己指定了父线程组就直接将线程添加到指定的线程组啦。

直接进入addThread方法:

final void addThread(Thread thread) throws IllegalThreadStateException {
synchronized (threadRefs) {
if (isDestroyed) {
throw new IllegalThreadStateException();
}
threadRefs.add(new WeakReference<Thread>(thread));
}
}

threadRefs是保存了线程组中包含的所有线程的弱引用,使用弱引用是为了防止内存溢出的,内存中只存在弱引用的对象是可以被回收的,不会造成内存泄露。但是又是谁调度的ThreadGroup的呢!

好像不太对!在哪调度的!!我想了又想猜了又猜!!突然灵光一现!!Looper!!这个专业负责调度线程的东西我怎么给忘了!!

在Looper的prepare方法中:

public static void prepare() {
prepare(true);
}
private static void prepare(booleanquitAllowed) {
if (sThreadLocal.get() != null) {
throw newRuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(newLooper(quitAllowed)); //新建一个looper对象,并保存到线程本地变量中
/// M: ALPS00297986
long instances =VMDebug.countInstancesOfClass(Looper.class, false);
// check if the looper instance over alimit, it should has some leakage.
if(100 < instances)
{
Log.e(TAG,"WARNING: The Looperclass instance count has over a limit(100). There should be some leakage ofLooper or HandlerThread.");
Log.e(TAG,"Looper classinstance count = " + instances);
Log.e(TAG,"Current ThreadName: " + Thread.currentThread().getName());
Thread.currentThread().getThreadGroup().list();
Thread.currentThread().dumpStack();
}//if
/// M: ALPS00297986
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); //新建一个消息队列
mThread = Thread.currentThread(); //保存当前线程
}

看到这一行没!!Thread.currentThread().getThreadGroup().list();哈哈哈,就是在Looper里面被调度的,哈哈哈,但是我悲伤地发现这个方法已经被更新了。。。

private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}

欲哭无泪,我忽然想到一个Looper对应一个Thread,所以Thread之间的调度应该不是Looper负责的。。~~(>_<)~~ ,我只好淡淡的滚回ThreadGroup里面继续寻找。。。

在ThreadGroup中所有的Thread的弱引用都被存到了一个List中,我试图找到调用了这个List的get方法的地方,也就是Thread被取出的地方,于是我找到了这里

/**
 * Copies into <param>enumeration</param> starting at
 * <param>enumerationIndex</param> all Threads or ThreadGroups in the
 * receiver. If <param>recurse</param> is true, recursively enumerate the
 * elements in subgroups.
 *
 * If the array passed as parameter is too small no exception is thrown -
 * the extra elements are simply not copied.
 *
 * @param enumeration array into which the elements will be copied
 * @param recurse Indicates whether subgroups should be enumerated or not
 * @param enumerationIndex Indicates in which position of the enumeration
 *        array we are
 * @param enumeratingThreads Indicates whether we are enumerating Threads or
 *        ThreadGroups
 * @return How many elements were enumerated/copied over
 */
private int enumerateGeneric(Object[] enumeration, boolean recurse, int enumerationIndex,
        boolean enumeratingThreads) {
    if (enumeratingThreads) {
        synchronized (threadRefs) {
            // walk the references directly so we can iterate in reverse order
            for (int i = threadRefs.size() - 1; i >= 0; --i) {
                Thread thread = threadRefs.get(i).get();
                if (thread != null && thread.isAlive()) {
                    if (enumerationIndex >= enumeration.length) {
                        return enumerationIndex;
                    }
                    enumeration[enumerationIndex++] = thread;
                }
            }
        }
    } else {
        synchronized (groups) {
            for (int i = groups.size() - 1; i >= 0; --i) {
                if (enumerationIndex >= enumeration.length) {
                    return enumerationIndex;
                }
                enumeration[enumerationIndex++] = groups.get(i);
            }
        }
    }

    if (recurse) {
        synchronized (groups) {
            for (ThreadGroup group : groups) {
                if (enumerationIndex >= enumeration.length) {
                    return enumerationIndex;
                }
                enumerationIndex = group.enumerateGeneric(enumeration, recurse,
                        enumerationIndex, enumeratingThreads);
            }
        }
    }
    return enumerationIndex;
}

看完翻译有些蒙圈,大概是把这些thread们全都拷贝了,可能是拷贝到了native层啥的之类的。。

突然我想起了度娘,于是搜了下“thread调度”惊讶的发现尼玛有个专门的调度器哟!!劳资居然妄想在代码里找到Thread是怎么调度的,还一步步坑进ThreadGroup和Looper!!简直气死宝宝!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值