Java创建线程的三种方式
一、通过Thread类的方式进行创建
步骤:
1、创建Thread的子类,重写run方法,run方法就表示线程需要完成的任务
2、创建Thread实例,也就是创建线程对象
3、使用start来启动线程(线程启动的唯一方法是通过 Thread 类的 start())
【继承Thread类的方式】
public class Thread02 extends Thread{
// 线程要执行的任务
@Override
public void run() {
System.out.println(this.getName()+" 线程执行了");
}
public static void main(String[] args) {
System.out.println("main线程运行的");
// 创建线程
Thread02 thread02 = new Thread02();
thread02.setName("t1线程");
// 启动线程(注意:线程启动的唯一方法是通过 Thread 类的 start() )
thread02.start();
}
}
【使用内部类】(通常我们都使用内部类的方式来创建线程)
public class Thread01 {
public static void main(String[] args) {
// 创建(注意:通常我们使用匿名内部类的方式,创建和启动线程)
Thread thread = new Thread("t1"){
// 要执行的任务
@Override
public void run() {
System.out.println("t1线程执行的任务");
}
};
// 启动线程
thread.start();
System.out.println("main方法输出");
}
}
二、通过Runnable接口的方式进行创建
步骤:
1、定义Runnable接口的实现类,重写run方法
2、创建Runnable实现类的实例,用这个实例来创建Thread对象
3、Thraed的start来进行启动(线程启动的唯一方法是通过 Thread 类的 start())
【实现Runnable接口的方式】
/**
* 使用接口的方式进行创建
*/
public class Thread04 implements Runnable{
@Override
public void run() {
System.out.println("t1线程运行了");
}
public static void main(String[] args) {
Thread04 thread04 = new Thread04();
// 线程启动的唯一方法是通过 Thread 类的 start()
Thread thread = new Thread(thread04);
thread.start();
System.out.println("main主线程进行运行的处理");
}
}
【使用内部类】(通常我们都使用内部类的方式来创建线程)
public class Thread03 {
public static void main(String[] args) {
// 创建(注意:通常我们使用匿名内部类的方式,创建和启动线程)
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("t1 线程执行了");
}
};
// 线程启动的唯一方法是通过 Thread 类的 start()
Thread thread = new Thread(runnable);
thread.start();
System.out.println("main线程进行运行处理!");
}
}
【使用lambda表达式】(通常我们使用lambda的方式来创建)
/**
* 使用lambda的方式,来进行创建
*/
public class Thread05 {
public static void main(String[] args) {
// Runnable接口使用的是 :@FunctionalInterface注解
Runnable runnable = () ->{
System.out.println("lambda的方式创建t1线程...");
};
// 线程启动的唯一方法是通过 Thread 类的 start()
new Thread(runnable).start();
System.out.println("main线程也在运行中......");
}
}
三、通过Callable接口的方式进行创建拥有返回值的
当我们在处理一个任务的时候,我们需要对外面进行返回值的处理,那么我们就压使用Callable来创建可以带返回值的线程。
public class Thread06 {
public static void main(String[] args) throws Exception{
// 创建具有返回值的线程
FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("t1线程进行运行处理了");
return "哈哈哈,我有返回值了";
}
});
// 线程启动的唯一方法是通过 Thread 类的 start()
Thread t1 = new Thread(futureTask);
t1.start();
// 获取返回值
String s = futureTask.get();
System.out.println("主线程获取到的返回值:"+s);
}
}
四、Thread和Runnable的比较处理
1)Thread的run处理
Thread方式是通过继承,我们需要对run方法进行重写的处理,然后在实际运行的时候,我们运行的就是自己重写的run方法
2)Runnable的run处理(源码分析)
// 1、new Thread(runnable).start();
// 我们把Runnable接口的实例传给Thread对象,调用对应的构造方法
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
// 2、把Runnable参数传给init
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
// 3、然后在传给另外一个重载的init方法(看下图中)
// 其中有一段,把Runnable传给了自己的变量
this.target = target;
// 4、run调用的时候,就会调用我们写的那个run了
@Override
public void run() {
if (target != null) {
target.run();
}
}
【相同点】
调用的都是自己创建的run方法