线程创建的方式(3种)

image.png

第一种,继承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 + "天,我是主线程~ ");
        }
    }
}

运行结果:
image.png

第二种,实现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 + "天,我是主线程~ ");
       }
   }
}  

运行结果:

image.png

第三种,实现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方法出现问题! ");
            }
        }
    }
}

运行结果:

image.png

总结

  • 不建议使用继承Thread类的方法来实现创建线程,因为Java中有单继承的局限性;
  • 推荐使用实现Runnale接口的方法来创建线程,避免单继承的局限性,灵活方便,方便同一个对象被多个线程使用;
  • 实现Callable接口可以定义返回值,可以抛出异常,但是步骤繁多,目前普通情况下不建议使用。