一、说起Android线程就不得不提到java,因为AndoridSDK中并没有开发新的线程,而是沿用了java的线程机制,所以接下来给大家深入讲解java中的线程,不足之处希望批评指正!!
二、Java中的线程:
一般来理解java中的线程有两种:1、
继承Thread类
/**
* 继承Thread方式
*/
private class TestThread extends Thread {
TestThread(String name) {
super(name);
}
@Override
public void run() {
//执行耗时操作
}
}
举个例子:
TestThread testThread1 = new TestThread ("线程一");
TestThread testThread2 = new TestThread ("线程二");
TestThread testThread3 = new TestThread ("线程三");
testThread1.start();
testThread2.start();
testThread3.start();
2、
实现Runnable接口
/**
* 实现Runnable方式
*/
private class implements Runnable {
@Override
public void run() {
//执行耗时操作
}
}
TestRunnable testRunnable = new TestRunnable();
Thread thread1 = new Thread(testRunnable , "线程一");
Thread thread2 = new Thread(testRunnable , "线程二");
Thread thread3 = new Thread(testRunnable , "线程三");
thread1.start();
thread2.start();
thread3.start();
举例:
package java.util.concurrent这个包里面,想必大家也比较清楚
其实,我这篇文章是介绍线程的原理,万变不离底层,不管是上层再怎么封装,只要知道了原理,其实也就明白了本质。
Thread主要函数
run()//包含线程运行时所执行的代码
start()//用于启动线程
sleep()/sleep(long millis)//线程休眠,交出CPU,让CPU去执行其他的任务,然后线程进入阻塞状态,sleep方法不会释放锁
yield()//使当前线程交出CPU,让CPU去执行其他的任务,但不会是线程进入阻塞状态,而是重置为就绪状态,yield方法不会释放锁
join()/join(long millis)/join(long millis,int nanoseconds)//等待线程终止,直白的说 就是发起该子线程的线程 只有等待该子线程运行结束才能继续往下运行
wait()//交出cpu,让CPU去执行其他的任务,让线程进入阻塞状态,同时也会释放锁
interrupt()//中断线程,自stop函数过时之后,我们通过interrupt方法和isInterrupted()方法来停止正在运行的线程,注意只能中断已经处于阻塞的线程
getId()//获取当前线程的ID
getName()/setName()//获取和设置线程的名字
getPriority()/setPriority()//获取和这是线程的优先级 一般property用1-10的整数表示,默认优先级是5,优先级最高是10,优先级高的线程被执行的机率高
setDaemon()/isDaemo()//设置和判断是否是守护线程
currentThread()//静态函数获取当前线程
Thread线程主要状态
(1) New 一旦被实例化之后就处于new状态
(2) Runnable 调用了start函数之后就处于Runnable状态
(3) Running 线程被cpu执行 调用run函数之后 就处于Running状态
(4) Blocked 调用join()、sleep()、wait()使线程处于Blocked状态
(5) Dead 线程的run()方法运行完毕或被中断或被异常退出,线程将会到达Dead状态
如何停止一个线程
通过上面的函数列表,我可以知道通过interrupt方法和isInterrupted()方法来停止正在运行的线程,首先必须先让线程处于阻塞状态
/**
* 销毁线程方法
*/
private void destroyThread() {
try {
if (null != thread && Thread.State.RUNNABLE == thread .getState()) {
try {
Thread.sleep(1000);
thread .interrupt();
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
thread = null;
}
}
可能会抛出InterupterExecption。
实现Runnable接口的多线程例子
/**
* 实现Runnable接口的类
*
*/
publicclass DoSomethingimplements Runnable {
private String name;
public DoSomething(String name) {
this.name = name;
}
public void run() {
for (int i = 0; i < 5; i++) {
for (long k = 0; k < 100000000; k++) ;
System.out.println(name + ": " + i);
}
}
}
/**
* 测试Runnable类实现的多线程程序
*
*/
publicclass TestRunnable {
publicstaticvoid main(String[] args) {
DoSomething ds1 = new DoSomething("阿三");
DoSomething ds2 = new DoSomething("李四");
Thread t1 = new Thread(ds1);
Thread t2 = new Thread(ds2);
t1.start();
t2.start();
}
}
看看日志:
李四: 0
阿三: 0
李四: 1
阿三: 1
李四: 2
李四: 3
阿三: 2
李四: 4
阿三: 3
阿三: 4
日志告诉我们,多线程并发是没有顺序的,当然通过一些方法,join,yeild是可以调控线程的执行顺序的,但这种东西在Android中的应用场景微乎其微。
况且本来Android的主线程就不允许有耗时操作,所以在Android应用开发过程中线程异步加载才是主流应用场景。
四、举例:
Android比较常见的场景就是异步加载网络图片,当页面上存在图片列表的时候,多线程下载就很重要,如果单线程下载,用户的网络不好,很可能导致很长时间页面没有出图,这样体验是很差的。
假如:现在一页加载5张图,分别来自5个url,我们开启了5个线程并发加载,有两种业务需求:1、异步刷新界面展示。2、当5张图片都下载完成后,返回界面展示。
第一种还好说,只要是图片下载完成一个接口回调刷新就完了。
但如果是第二种呢,怎么判断5张图片都下载完了呢??这里其实也不难,ThreadCount就可以搞定,ThreadCount我认为他就是一个标记(TAG),当你int ThreadCount =5;时候,假设有一个图片记载完成,你就在返回结果ThreadCount--;并判断
if(ThreadCount ==0){
//刷新,展示数据
};
直到所有的图片都应经下载完成,就能执行if里面的代码。
仔细看看Okhttp3
还有响应式Rxjava2
都用到了线程标记。
最后还是那句话,万变不离其宗,希望大家互相学习,掌握学习方法,不断提高!