该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!!
从本篇博文开始Android并发编程系列。由于笔者水平有限,如果博文之中有任何错误或者纰漏之处,还请不吝赐教。
在Android SDK中并没有提供新颖的线程实现方案,使用的依旧是JDK中的线程。在Java中开启新线程有3中常见的方式
public class ThreadA extends Thread {
@Override
public void run() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName());
}
}
//测试的主线程
public class Main {
public static void main(String[] args){
ThreadA threadA = new ThreadA();
threadA.setName("threadA");
threadA.start();
System.out.println("主线程"+Thread.currentThread().getName());
}
}
public class ThreadB implements Runnable{
@Override
public void run() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
//测试的主线程
public class Main {
public static void main(String[] args){
ThreadB threadB = new ThreadB();
//注意这里启动的方式跟方式1不一样
Thread thread = new Thread(threadB);
thread.setName("threadB");
thread.start();
System.out.println("主线程"+Thread.currentThread().getName());
}
}
public class ThreadC implements Callable<String> {
@Override
public String call() throws Exception {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Thread.currentThread().getName();
}
}
public class Main {
public static void main(String[] args){
ThreadC threadC = new ThreadC();
//FutureTask 后续会讲到,先知道有怎么个实现方式
FutureTask<String> feature = new FutureTask<>(threadC);
//注意启动方式有点不一样;
Thread thread1 = new Thread(feature);
thread1.setName("threadC");
thread1.start();
//注意细细体会这个,只有主线程get了,主线程才会继续往下面执行
try {
System.out.println(feature.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("主线程"+Thread.currentThread().getName());
}
}
上面简单的介绍了3种开启线程的方式,接下来我们来看一下Java的内存模型,因为后续文章讲到的许多知识都需要这个作为基础。
JMM规定JVM有主内存(Main Memory)和工作内存(Working Memory),主内存其实就是我们平常所说的Java堆内存,存放所有类实例变量等,这部分内存是多个线程共享的;工作内存里存放的则是线程从主内存拷贝过来的变量以及访问方法得到的临时变量,这部分内存为线程私有,其他的线程不能访问。
注:上面所说的拷贝并不是拷贝整个对象实例到工作内存,虚拟机可能拷贝对象引用或者对象字段,而不是整个对象。
主内存与工作内存的关系如下图所示
主内存与工作内存之间具体的交互协议,被定义了以下8种操作来完成,虚拟机实现时必须保证每一种操作都是原子的、不可再分的。
8种操作的实现规则:
整个并发编程所遇到的问题可以说是以下三个问题的变种。
可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改,可见性由volatile支持,除了volatile以外,synchronize和final关键字,synchronize的可见性是由”对一个变量执行unlock操作之前,必须先把此变量同步回主内存中“这条规则保证的,而final关键字是指当final修饰的字段在构造函数中一旦初始化完成,并且构造器没有把this的引用传递出去,那在其他线程中就能看见final字段的值,无须同步就能被其他线程正确访问
在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在happens-before关 系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间。 与程序员密切相关的happens-before规则如下。
JMM的happens-before规则不但简单易懂,而且也向程序员提供了足够强的内存可见性保证
本篇文章简单分析了下线程的启动方式以及JMM模型,为后面的文章铺垫一下。
Java多线程与锁
此致,敬礼