目录
1.Thread类:
继承Thread类的创建方式:
- 定义Thread类的子类,并重写该类的 run() 方法,该 run() 方法的方法体就代表了线程需要完成的任务。
- 创建Thread子类实例,即创建了线程的对象
- 调用线程对象的start() 方法来创建并启动线程。
public class HelloThread extends Thread{
@Override
public void run() {
System.out.println("继承Thread类--创建线程");
}
public static void main(String[] args) {
HelloThread ht = new HelloThread();
ht.start();
}
}
2.Runable接口
- 定义Runable接口的实现类,并且重写该接口的run() 方法,该run() 方法的方法体就是线程的线程执行体
- 创建Runable实现类的实例,并且以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象。
public class HelloRunable implements Runnable{
@Override
public void run() {
System.out.printf("实现Runable 接口创建线程");
}
public static void main(String[] args) {
HelloRunable helloRunable = new HelloRunable();
Thread thread = new Thread(helloRunable);
thread.start();
}
}
3.Callable接口
- 创建Callable接口的实现类,并且实现 call() 方法,该call() 方法将作为线程的执行体,且该call()方法又返回值,再创建Callable实现类的实例
- 使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
- 使用FutureTask对象作为Thread对象的target创建并且启动新线程。
- 使用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
public class HelloCallable {
public static void main(String[] args) {
//使用 FutureTask对象 创建
//Lambda表达式
FutureTask futureTask = new FutureTask(() -> {
int j = 0;
for (int i = 0; i < 100; i++) {
j=i+j;
}
return j;
});
// 创建线程
Thread thread = new Thread(futureTask);
// 启动线程
thread.start();
//使用这种方式可以拿到线程的返回值
try {
//在未获取到结果前会阻塞等待
futureTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
4.线程池方式
详细请见
5. 线程上下文切换(以Linux为例)
JDK1.2 版本前java是ULT模式;jvm进程自己创建线程;此种方式是伪线程方式;
JDK1.2版本后java是KLT模式;java线程与内核线程 1:1 映射;比如利用Linux的pthread类库实现
线程的上下文切换势必会涉及到用户态到内核态的转变;线程的运行信息执行到哪个指令(线程的状态信息等)都保存在CPU(高速缓存:寄存器L1,L2,L3)中。如果线程还未执行完成CPU会把执行的中间信息存储到TSS(任务状态段)中,当线程再次分配到CPU时间片段的时候会从这回读数据;
上下文切换的开销包括直接开销和间接开销。
直接开销有如下几点:
- 操作系统保存回复上下文所需的开销
- 线程调度器调度线程的开销
间接开销有如下几点:
- 处理器高速缓存重新加载的开销
- 上下文切换可能导致整个一级高速缓存中的内容被冲刷,即被写入到下一级高速缓存或主存