目录:
- 创建多线程的三种方式
- extends Thread
- implements Runnable
- 匿名类
- 线程创建方式
- 有关构造函数中使用匿名类的说明
- 多线程的核心理论
- 共享性
- 互斥性
- 原子性
- 可见性
- 有序性
- synchronized
- 使用方法
- 内核剖析
- volatile
- 使用方法
- 使用场景
- 多线程生命周期图
- 线程安全的容器
多线程的内容有的是笔者自己总结,有的会直接推荐优质博客。
自己总结的部分一般包含个人实践时的经验和需要注意的坑点。
创建多线程的三种方式
三种方式的核心均是对Thread类中run方法进行override
1.extends Thread
public class CreateThreadMethod {
public static void main(String[] args) {
extendsMethod thread = new extendsMethod();
thread.start();
}
}
class extendsMethod extends Thread {
@Override
public void run() {
for (int i = 9; i >= 0; i--) {
System.out.println("extendsMethod's Thread:" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
}
2.implements Runnable
public class CreateThreadMethod {
public static void main(String[] args) {
Thread thread = new Thread(new implementsMethod());
thread.start();
}
}
class implementsMethod implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("implementsMethod's Thread:" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
}
3.匿名类
多线程创建方式:
public class CreateThreadMethod {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 9; i >= 0; i--) {
System.out.println("The third method's Thread:" + 3 * i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
});
thread.start();
}
}
有关匿名类在构造函数中使用的说明:
先看如下例子:
public class ThisEscape {
private final int num;
public ThisEscape(EventSource source) {
//在构造函数中直接使用匿名类
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
num = 42;
}
private void doSomething(Event e) {
if (num != 42) {
System.out.println("Race condition detected at " +
new Date());
}
}
}
上述class编译之后分为两部分:
outer class:
public class ThisEscape {
private final int num;
public ThisEscape(EventSource source) {
source.registerListener(new ThisEscape$1(this));
num = 42;
}
private void doSomething(Event e) {
if (num != 42)
System.out.println(
"Race condition detected at " + new Date());
}
static void access$000(ThisEscape _this, Event event) {
_this.doSomething(event);
}
}
anonymous inner class:
class ThisEscape$1 implements EventListener {
final ThisEscape this$0;
ThisEscape$1(ThisEscape thisescape) {
this$0 = thisescape;
super();
}
public void onEvent(Event e) {
ThisEscape.access$000(this$0, e);
}
}
试想:如果一个线程足够快,那么就有可能在num
还被初始化为42之前,匿名类已经调用了doSomething()
这个时候就会抛出NullPointerException
那么一个类的构造函数要怎么写才会避免类似的错误出现呢?
- 永远不要在构造器内创建内部类,无论是匿名类,还是
static
、non-static
- 在构造器中不要把
this
当成参数传递给其他的类或方法 - 在构造器中只调用
private
方法
多线程的核心理论
详见博客:多线程的核心理论
synchronized:
对方法加锁 == 对对象加锁,即synchronized this
关于synchronized
的内核剖析详见博客:synchronized的内核剖析
volatile
个人使用经验是:对于一些标志位,常采用volatile
关于volatile的具体解析:volatile
多线程生命周期图
思考:图中涉及的wait方法和sleep方法,为什么wait方法在Object类,而sleep方法在Thread类?
两者都可以让线程暂停一段时间,但是本质的区别在于sleep方法是线程的运行状态控制,而wait方法是线程之间的通讯
线程安全的容器:
详见博客:线程安全的容器