文章目录
- 1.什么是线程
- 2. 线程创建和运行
1.什么是线程
进程是操作系统进行资源分配和调度的基本单位,线程是 CPU 分配的基本单位。
- 程序计数器用来记录线程当前要执行的指令地址。CPU一般是使用时间片轮转方式让线程轮询占用的,程序计数器是记录线程让出CPU时的执行地址的,待再次分配到时间片时线程就可以从自己私有的计数器指定地址继续执行。另外需要注意的是,如果执行的是 native 方法那么 pc计数器记录的是 undefned 地址,只有执行的是 Java 代码时 pc计数器记录的才是下一条指令的地址。
- 栈用于存储线程的局部变量,调用栈帧。
- 堆里面主要存放 new创建的对象实例。
- 方法区存放 加载的类、常量及静态变量等信息。
2. 线程创建和运行
java中创建线程的三种方式:继承Thread类,实现Runnable接口,实现Callable接口 。
- 继承Thread类
public class MyThread extends Thread{
@Override
public void run() {
System.out.println (" I am a child thread,线程id:"+this.getId()+"线程名字:"+this.getName()) ;
System.out.println (" I am a child thread,线程id:"+Thread.currentThread().getId()+"线程名字:"+Thread.currentThread().getName()) ;
System.out.println (System.getProperty("java.version")+","+System.getProperty("java.vendor")+","+System.getProperty("java.vendor.url"));
}
public static void main(String[] args) {
MyThread thread= new MyThread();//创建线程
thread.start();// 启动线程
}
}
- 实现Runnable接口
public class RunableTask implements Runnable{
@Override
public void run() {
System.out.println (" I am a child thread,线程id:"+Thread.currentThread().getId()+"线程名字:"+Thread.currentThread().getName()) ;
}
public static void main(String[] args) {
RunableTask task = new RunableTask();
new Thread(task).start() ;
new Thread(task).start() ;
}
}
- 实现Callable接口
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallerTask implements Callable<String> {
@Override
public String call() throws Exception {
return "hello";
}
public static void main(String[] args) {
// 创建异步任务
FutureTask<String> futureTask=new FutureTask<>(new CallerTask()) ;
//启动线程
new Thread(futureTask).start() ;
try {
//等待任务执行完毕,并返回结果
String result = futureTask.get();
System.out.println(result);
} catch (ExecutionException | InterruptedException e){
e.printStackTrace();
}
}
}
调用了start方法后才真正启动了线程。其实调用start方法后线程并没有马上执行而是处于就绪状态,这个就绪状态是指该线程已经获取了除 CPU 资源外的其他资源,等待获取 CPU 资源后才会真正处于运行状态。一旦 run 方法执行完毕,该线程就处于终止状态。
使用继承方式的好处是,在run()方法内获取当前线程直接使用this就可以了,无须使用 Thread.currentThread()方法;不好的地方是Java不支持多继承,继承了 Thread 类不能继承其他类。另外任务与代码没分离,多个线程执行一样的任务时需要多份任务代码。
Runable接口实现的,两个线程可以共用一个 task 代码逻辑,可以给RunableTask添加参数进行任务区分。
Callable 接口实现的任务有返回值,通过futureTask.get()等待任务执行完毕并返回结果。