DEV Community

Liu yu
Liu yu

Posted on

Java并发笔记

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);
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

会发现主线程和子线程的代码交替执行

需要说明把 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();
    }
}
Enter fullscreen mode Exit fullscreen mode

输出为

下载了文件名为:2.jpg
下载了文件名为:3.jpg
下载了文件名为:5.jpg
下载了文件名为:4.jpg
下载了文件名为:6.jpg
下载了文件名为:1.jpg
Enter fullscreen mode Exit fullscreen mode

RunnableCallable区别


// Runnable
public interface Runnable {
    void run();
}

// Callable
public interface Callable<V> {
    V call() throws Exception;
}

Enter fullscreen mode Exit fullscreen mode

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(); // 启动线程,线程体开始执行
Enter fullscreen mode Exit fullscreen mode

3. 总结

  • 所有多线程写法,最终都要依赖Thread对象的start()方法来真正创建和启动线程。
  • 你写的run()方法、RunnableCallable等只是“线程体”,是线程要执行的任务内容。
  • “线程体”是任务,“线程”是执行任务的实体。

面试答法:

Java真正创建线程的方式只有new Thread().start(),其他方式只是任务的封装和管理。线程体是线程要执行的代码,线程是调度和运行这些代码的实体。

Top comments (0)