创建线程有几种方式:
- 自定义类继承Thread(如下面的AThread),然后使用Thread.start方法启动线程
- 创建类,实现Runnable,通过Thread的构造函数来启动,有时也用于ThreadPoolExecutor线程池的一些execute方法中
- Callable,提到Callable就需要知道Future,通常情况下Callable用于线程池execute或submit方法中,获取线程的返回结果。
- Executors框架的几个常用方法,调用execute或者submit方法即可。
public class CreateThread { @Test public void useThread() throws InterruptedException { AThread newThread = new AThread("线程1"); newThread.start(); } @Test public void implementsRunnable() { new Thread(()->{ System.err.println(Thread.currentThread().getName() + " is running."); }, "线程2").start(); } @Test public void useCallable() throws ExecutionException, InterruptedException { Callablecallable = new Callable () { @Override public String call() throws Exception { return "use callable test."; } }; ExecutorService executorService = Executors.newFixedThreadPool(1); Future future = executorService.submit(callable); System.err.println(future.get()); } class AThread extends Thread { public AThread(String name) { super(name); } @Override public void run() { System.err.println(Thread.currentThread().getName() + " is running."); } }}
Race Condition
知识前提:了解一下《深入理解JVM虚拟机》Chapter2.2,Java虚拟机运行时数据区。
方法区(类变量、类信息等)、堆(heap)是线程共享的数据区;
虚拟机栈、本地方法栈、程序计数器(唯一一个不会OOM的区域)线程隔离。
这里以i++为例
首先介绍一下:
public class Test { int test1() { int i = 1; return i++; } int test2() { int i = 1; return ++i; }}
javac 编译成字节码文件,javap -verbose Test.class查看字节码信息:
int test1(); descriptor: ()I flags: Code: stack=1, locals=2, args_size=1 0: iconst_1 1: istore_1 2: iload_1 3: iinc 1, 1 6: ireturn LineNumberTable: line 15: 0 line 16: 2 int test2(); descriptor: ()I flags: Code: stack=1, locals=2, args_size=1 0: iconst_1 1: istore_1 2: iinc 1, 1 5: iload_1 6: ireturn LineNumberTable: line 19: 0 line 20: 2
i++分为三步:iconst_1——数字1进栈,istore_1——将栈顶int型数值存入第二个局部变量,从0开始计数
iinc 1: 加1
注意到:i++是先load,再inc;而++i是先inc再load
线程的几种状态
参考《深入理解Java虚拟机》chapter12,线程状态分为5种:
- 新建(New):创建后未运行的线程
- 运行(Runnable):Runnable包含了操作系统线程状态中的Running和Ready,有可能正在执行,也有可能等待着CPU为它分配执行时间。
- 无限期等待(Waiting):无等待时间的Object.wait()方法,Thread.join()方法,LockSupport.park()方法。
- 限期等待(Timed Waiting):Thread.sleep(),带timeout参数的wait(),join()方法,LockSupport.parkNanos(),LockSupport.parkUntil();
- 阻塞(Blocked):等待获取一个排它锁。
- 结束(Terminated):已终止线程的线程状态。
各状态之间的转换如下图(来自:):