线程创建的方式(3种)
第一种,继承Thread类创建线程
- 自定义线程类,继承Thread类;
- 重写run()方法,编写线程的执行体;
- 创建线程对象,调用start()方法。
public class TestThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("第 " + i + "天,我在学习多线程~ ");
}
}
public static void main(String[] args) {
TestThread testThread = new TestThread();
testThread.start();
for (int i = 0; i < 200; i++) {
System.out.println("第 " + i + "天,我是主线程~ ");
}
}
}
运行结果:
第二种,实现Runnale接口,来创建线程
- 自定义类实现Runnale接口;
- 重写run()方法;
- 执行前需要丢入Runnale接口的实现的的对象,调用start()方法。
public class TestThread3 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("第 " + i + "天,我在学习多线程~ ");
}
}
public static void main(String[] args) {
TestThread3 testThread3 = new TestThread3();
new Thread(testThread3).start();
for (int i = 0; i < 200; i++) {
System.out.println("第 " + i + "天,我是主线程~ ");
}
}
}
运行结果:
第三种,实现Callable接口
- 自定义类实现Callable接口;
- 重写call()方法;
- 创建实现类的对象;
- 创建执行服务ExecutorService;
- 提交执行;
- 获取执行的结果;
- 关闭服务。
使用多线程下载网络图片的案例来演示:
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
public class TestThread6 implements Callable<Boolean> {
private String url;
private String name;
public TestThread6(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public Boolean call() throws Exception {
WebDownload webDownload = new WebDownload();
webDownload.download(url, name);
System.out.println("开始下载: " + name);
return true; //目前先全部设置返回值为true
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestThread6 t1 = new TestThread6("http://image.qiyuan.run/co.jpg?imageView2/2/w/700 ", "1.gif ");
TestThread6 t2 = new TestThread6("http://image.qiyuan.run/ch.jpg?imageView2/2/w/700 ", "2.gif ");
TestThread6 t3 = new TestThread6("http://image.qiyuan.run/ch.jpg?imageView2/2/w/700 ", "3.gif ");
//1,创建执行的服务,放3个线程进去
ExecutorService service = Executors.newFixedThreadPool(3);
//2,提交执行
Future<Boolean> r1 = service.submit(t1);
Future<Boolean> r2 = service.submit(t2);
Future<Boolean> r3 = service.submit(t3);
boolean res1 = r1.get(); //3,获取结果
boolean res2 = r2.get();
boolean res3 = r3.get();
service.shutdown(); //4,记得关闭服务
System.out.println(res1 + "-- " + res2 + "-- " + res3 + "-- ");
}
class WebDownload {
public void download(String url, String name) {
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("download方法出现问题! ");
}
}
}
}
运行结果:
总结
- 不建议使用继承Thread类的方法来实现创建线程,因为Java中有单继承的局限性;
- 推荐使用实现Runnale接口的方法来创建线程,避免单继承的局限性,灵活方便,方便同一个对象被多个线程使用;
- 实现Callable接口可以定义返回值,可以抛出异常,但是步骤繁多,目前普通情况下不建议使用。