两种传统传统方式创建:(thread、Runnable), 线程池方式ExcutorServicePool
传统方式创建线程:
1、继承Thread类,重写run方法
2、实现Runnable接口,覆盖接口中的run方法,然后将接口实现扔给Thread
run方法探秘:
Thread源码中的run方法,如下:
@Override
public void run() {
if (target != null) {
target.run();
}
}
由代码知道,run方法中是一个if判断,target不为空,就可以执行 target.run()
target是什么??
private Runnable target;
由代码知,target就是一个Runnable接口。
最后,进入Runnable代码:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Runnable中原来还是run方法;
我自己的理解为:Thread方法实现run方法要经历一个if语句的判断,直接不要if判断了,直接重写run; 而Runnable,直接调用重写run即可
总结:为什么创建线程有两种方式?
第一种:你不是要先进行if
判断么?我现在不判断了,我把你的if
干掉,我在run()
方法中自己写代码,想干啥就干啥,即重写Thread中的run()
方法,;
第二种:你不是要先进行if
判断么?行,给你一个Runnable接口让你判断,但你还是得调用我Runnable中的run()
方法啊,那我重写我Runnable中的run()
方法不就行了!
1、Thread创建线程(继承Thread)
(1)继承Thread,调用run方法
(2)start()开启线程
public static void main(String[] args){
Thread thread1 = new Thread(){
@Override
public void run(){
try {
Thread.sleep(500);//让线程休息500毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());//打印出当前线程名
}
};
thread1.start();
}
2、Runnable创建线程(实现Runnable接口)
(1)实现Runnable接口,调用run方法
(2)start()开启线程
public static void main(String[] args){
Thread thread2 = new Thread(new Runnable(){
@Override
public void run(){
try(){
Thread.sleep(1000);
} catch(Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()); //让线程休息500毫秒
}
});
thread2.start();
}
3、Thread和Runnable同时创建线程
public static void main(String[] args){
new Thread(new Runnable(){//实现runnable接口
@Override
public void run(){
try(){
Thread.sleep(1000);
} catch(Exception e){
e.printStackTrace();
}
System.out.println("Runnable:" + Thread.currentThread().getName()); //让线程休息500毫秒
}
}){ //实现thread
@Override
public void run(){
try {
Thread.sleep(500);//让线程休息500毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread:" + Thread.currentThread().getName());//打印出当前线程名
}
}.start();
}
经过运行发现,执行的是Thread中的run方法。
总结:
执行start()
后,肯定先在子类中找run()
方法,找到了,父类的run()
方法自然就被干掉了,所以会打印出Thread:,如果我们现在假设子类中没有重写run()
方法,那么必然要去父类找run()
方法,父类的run()
方法中就得判断是否有Runnable传进来,现在有一个,所以执行Runnable中的run()
方法,那么就会打印Runnable:出来。
4、ExcutorServicePool线程池方法,创建线程
private ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //没有精确到毫秒
public void scheduledStatusNotify() {
ScheduledFuture<?> future = pool.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
..........
}
});
}
线程池的方式创建线程本质上还是通过第二种方法(Runnable接口),重写run方法