先给一道面试题,线程有几种实现方式?
基本上自己学过java的人可能都会说两种,但是其实线程有三种实现方式,不过有一种用的比较少而已。我们先把这三种给出来。
1、继承Thread类
2、实现Runnable接口
3、实现Callable接口
接下来我们分别编写一下代码:
1、继承Thread类
/**
* @author Hercules
* @version 创建时间:2020年2月14日 上午9:37:32
* 类说明
*/
public class MyThread extends Thread{
private String name;
public MyThread(String name) {
super();
this.name = name;
}
//当前线程所做的事情就写在run方法中
@Override
public void run() {
super.run();
for(int i = 1;i<100;i++) {
System.out.println(name+i);
}
}
public static void main(String[] args) {
MyThread myThread1 = new MyThread("张三");
MyThread myThread2 = new MyThread("李四");
//启动线程
myThread1.start();
myThread2.start();
}
}
结果如下:
可以看到虽然很不规则但是两个线程还是交叉执行了,当然这里的线程同时其实不是绝对的同时,这里可以看到当李四数到9的时候战三数到了18。其实这里的内容只要交替了就可以证明他们是同时执行的。
2、实现Runnable接口
这里的方法就是将Runnable接口类型的对象传入Thread中,Thread中的run方法会默认调用Runable接口类型对象的run方法实现线程。
实现Runnable接口 实现接口可以多实现, 当使用实现Runnable接口后,还可以继续继承其他的类和实现其他的接口,扩展性没有变化,可以多个线程共享一个对象
/**
* @author Hercules
* @version 创建时间:2020年2月14日 上午9:52:48
* 类说明
*/
public class MyRunnable implements Runnable{
@Override
public void run() {
/*
* 当前线程要做的事情
*/
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
结果如下:
最后一个方法我们等会儿再说先说一下线程的生命周期
这个也是面试的时候会问的问题,我对于理论知识以前是比较不屑的,但是理论确实很重要,我们必须正视这个问题。
a.创建线程对象
b.调用start方法,线程就处于就绪状态
就绪状态的时候:会将该线程加入线程队列(先进先出),等待cpu资源
c.获取到cpu资源的时候,线程处于执行状态
当处于执行状态的时候:线程如果阻塞(例如:Thread.sleep(),IO读取阻塞),CPU资源会释放,其他线程会占用CPU资源,直到阻塞原因消失,重新加入队列等待cpu资源,等待cpu资源的时候会从阻塞处继续执行(而不是重新执行run方法)
线程如果执行完了run方法,线程自然结束(线程死亡)
3、实现Callable接口
这里通过重写call方法实现
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
* @author Hercules
* @version 创建时间:2020年2月14日 上午10:10:07
* 类说明
*/
public class MyCallable implements Callable<Integer>{
@Override
public Integer call() throws Exception {
/*
* 该方法就是线程要做的事情
*/
for (int i = 0; i < 10000; i++) {
System.out.println(i);
}
return 100;
}
public static void main(String[] args) {
//callable中有一个call方法
MyCallable myCallable = new MyCallable();
//中间需要中转一下
//task中有一个run方法调用了callable的call方法
FutureTask<Integer> task = new FutureTask<Integer>(myCallable);
//thread的run方法调用了task的run方法
Thread thread = new Thread(task);
thread.start();
}
}