0
点赞
收藏
分享

微信扫一扫

Android并发编程高级面试题汇总(含详细解析 十五)

Android并发编程高级面试题汇总最全最细面试题讲解持续更新中👊👊 👀你想要的面试题这里都有👀 👇👇👇

pthread 了解吗?new 一个线程占用多少内存?(快手)

这道题想考察什么?

是否清楚创建线程的代价

考察的知识点

线程底层原理

线程资源消耗

考生应该如何回答

pthread

pthread一般是指 POSIX的线程标准,是一套定义了创建和操纵线程的API。 一般用于Unix-like系统,如Linux、Mac OS。

Java的跨平台基于虚拟机,由JVM屏蔽不同的操作系统的底层实现。在Java中创建线程,运行在Linux中(包括Android),实际上就是封装了pthread(《4.23 如何开启一个线程,开启大量线程会有什么问题,如何优化? 》)。

线程内存

在Java中每个线程需要分配线程内存,用来存储自身的线程变量。在JDK 1.4中每个线程是256K的内存,在JDK 1.5之后每个线程是1M的内存。

HandlerThread是什么?

这道题想考察什么?

是否了解HandlerThread与真实场景使用,是否熟悉HandlerThread

考察的知识点

HandlerThread的概念在项目中使用与基本知识

考生应该如何回答

HandlerThread原理

HandlerThread就是一个自带Handler的Thread,更确切的讲是一个内含有Looper的Thread,这点从HandlerThread的源码注释就可以得知。

/**
 * Handy class for starting a new thread that has a looper. The looper can then be 
 * used to create handler classes. Note that start() must still be called.
 */

用于启动具有looper的新线程的方便类。 可以使用looper来创建处理程序类。 注意仍然必须调用start()来启动。

要想获取一个与之绑定的Handler可以通过内置的getThreadHandler()方法获得。

public Handler getThreadHandler() {
	if (mHandler == null) {
		mHandler = new Handler(getLooper());
	}
	return mHandler;
}

那么,当从调用handlerThread.start()方法那一刻开始,其内部发生了什么呢?Thread的start()方法注释如下。

/**
 * Causes this thread to begin execution; the Java Virtual Machine
 * calls the <code>run</code> method of this thread.
 */

导致此线程开始执行; Java虚拟机调用此线程的run方法。

看看HandlerThread的run()方法。

@Override
public void run() {
	mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
    	mLooper = Looper.myLooper();
    	notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

run()方法里没有什么陌生的东西,先是调用了Looper.prepare()方法创建一个Looper,然后加了一个同步锁获取当前线程的Looper对象赋值到mLooper上并唤醒所有线程,再然后设置当前线程优先级,再然后调用了onLooperPrepared()方法,最后调用Looper.loop()开启循环。

可能会有些好奇为什么在赋值mLooper时要加同步锁,后面会有解释。

看到这里,你可能会想,这跟我们自己继承Thread在run方法里开启一个Looper没什么两样吗,的确,但是官方也说了HandlerThread是一个方便类,方便我们在子线程使用Handler。

对了,上面run()方法里的onLooperPrepared()方法是干什么的?

/**
 * Call back method that can be explicitly overridden if needed to execute some
 * setup before Looper loops.
 */
 protected void onLooperPrepared() {
 }

如果需要在Looper循环之前执行某些设置,可以复写此方法。

emmm,那run()方法里加同步锁是为什么呢?

如果你不想通过HandlerThread为我们提供的getThreadHandler()方法来获取一个Handler,HandlerThread也提供了getLooper()方法为你提供Looper对象创建实现自己的Handler。

public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

这下就明白为啥在run()方法同步锁里赋值mLooper完成后要在再唤醒所有线程了。因为此方法将阻塞线程,直到looper已初始化。

整个HandlerThread类也就不到200行代码,除了上面那些,它还封装了线程不使用时退出Looper的方法。

public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

可以看出,HandlerThread真的是一个方便类啊,很方便。

使用场景

相比于普通的Thread,我为什么要使用HandlerThread?

对于普通的Thread,执行一遍就结束了,一个实例不能start多次,如果你不止一次启动同一个示例,那么将会抛出一个IllegalThreadStateException异常,这些在Thread的源码里都有注释写到。

/**
 * 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.         
 *             如果线程已经启动将抛出IllegalThreadStateException异常
 */

如果需要频繁的操作数据库、大文件、请求网络,就需要频繁的创建Thread示例调用start(),又或是需要执行一系列串行操作;而HandlerThread由于自带Handler,也就相当自带了一个任务队列,需要进行耗时操作的时候只要通过Handler执行send或post系列操作就行,不再需要频繁创建Thread,节省资源。


举报

相关推荐

0 条评论