start()
和run()
的区别
package com.process;
class MyThread extends Thread {
@Override
public void run() {
for(int i=0;i<1000;i++) {
// 模拟线程执行的任务
System.out.println("Son thread is running: " + i);
}
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
for(int i=0;i<1000;i++) {
// 模拟主线程执行的任务
System.out.println("Main thread is running: " + i);
}
}
}
会发现主线程和子线程的代码交替执行
需要说明把 thread.start()
换成thread.run()
并不会创建一个线程,run()
只是进行方法的调用!
另一个例子
继承Thread类、实现Runnable接口、实现Callable接口分别来创建线程
其中Java是单继承,如果继承了Thread,就不能继承其他类,扩展性差,所以实际开发中一般不使用继承Thread类的方法!
package com.process;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import org.apache.commons.io.FileUtils;
class MyThread extends Thread {
final private String url;
final private String name;
public MyThread(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
webDownloader wd = new webDownloader();
wd.downloader(url, name);
System.out.println("下载了文件名为:" + name);
}
}
class MyRunneable implements Runnable{
final private String url;
final private String name;
public MyRunneable(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run()
{
webDownloader wd = new webDownloader();
wd.downloader(url, name);
System.out.println("下载了文件名为: "+ name);
}
}
class webDownloader {
public void downloader(String url, String name) {
try {
FileUtils.copyURLToFile(
new URL(url),
new File(name)
);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
//1.用Thread类的子类来实现多线程
MyThread t1 = new MyThread("https://img-s.msn.cn/tenant/amp/entityid/AA1Hk338.img?w=768&h=482&m=6", "1.jpg");
MyThread t2 = new MyThread("https://img-s.msn.cn/tenant/amp/entityid/AA1HhWxW.img?w=584&h=328&m=6", "2.jpg");
MyThread t3 = new MyThread("https://img-s.msn.cn/tenant/amp/entityid/AA1HhUci.img?w=584&h=328&m=6", "3.jpg");
t1.start();
t2.start();
t3.start();
//2.用Runnable接口来实现多线程
Thread t4=new Thread(new MyRunneable("https://img-s.msn.cn/tenant/amp/entityid/AA1HhUci.img?w=584&h=328&m=6", "4.jpg"));
Thread t5=new Thread(new MyRunneable("https://img-s.msn.cn/tenant/amp/entityid/AA1HhWxW.img?w=584&h=328&m=6", "5.jpg"));
Thread t6=new Thread(new MyRunneable("https://img-s.msn.cn/tenant/amp/entityid/AA1Hk338.img?w=768&h=482&m=6", "6.jpg"));
t4.start();
t5.start();
t6.start();
}
}
输出为
下载了文件名为:2.jpg
下载了文件名为:3.jpg
下载了文件名为:5.jpg
下载了文件名为:4.jpg
下载了文件名为:6.jpg
下载了文件名为:1.jpg
Runnable
和Callable
区别
// Runnable
public interface Runnable {
void run();
}
// Callable
public interface Callable<V> {
V call() throws Exception;
}
java线程的本质
这里梳理一下
1. 线程的本质创建方式
无论你是继承Thread类、实现Runnable接口、实现Callable接口、还是用线程池,
最终真正创建线程的,都是new Thread().start()
。
- 继承Thread类:你写的其实是线程要执行的“任务体”,本质还是
Thread
对象在调度。 - 实现Runnable/Callable接口:你只是把任务封装成对象,最后还是交给
Thread
来启动。 - 线程池/CompletableFuture:底层也是维护了一组
Thread
对象,帮你统一管理和复用。
所以,Java真正意义上的线程创建,只有new Thread().start()
这一种。其他方式只是任务的封装和管理方式。
2. 线程体和线程的区别
-
线程(Thread):是操作系统调度的最小执行单元,Java里表现为
Thread
对象。 -
线程体:是线程要执行的具体代码,也就是你写在
run()
方法里的内容(任务体)。
举例:
class MyRunnable implements Runnable {
public void run() {
// 这里就是线程体
System.out.println("任务执行");
}
}
Thread t = new Thread(new MyRunnable()); // 这里创建了线程对象
t.start(); // 启动线程,线程体开始执行
3. 总结
- 所有多线程写法,最终都要依赖
Thread
对象的start()
方法来真正创建和启动线程。 - 你写的
run()
方法、Runnable
、Callable
等只是“线程体”,是线程要执行的任务内容。 - “线程体”是任务,“线程”是执行任务的实体。
面试答法:
Java真正创建线程的方式只有
new Thread().start()
,其他方式只是任务的封装和管理。线程体是线程要执行的代码,线程是调度和运行这些代码的实体。
Top comments (0)