run()和start()方法区别

进程和线程的区别

进程系统进行资源分配和调度的基本单位, 线程进程的子任务,是CPU调度和分派的基本单位

进程拥有完整的资源平台,如堆和方法区;线程只共享程序计数器和堆这些必不可少的资源

线程也拥有就绪、运行、阻塞三种状态,同样可以进行状态之间的转换

线程相比进程能减少开销:

  1. 线程创建时间更快:进程在创建过程中,还需要涉及内存管理信息和文件管理信息等诸多资源管理信息。而线程则无需这些,只会共享他们,同理,线程的终止时间比进程的要快

  2. 在同一进程中的线程切换要比进程切换快:因为线程具有相同的地址空间(虚拟内存共享),同一个进程的线程都具有同一个页表,那么在切换的时候不需要切换页表。而对于进程之间的切换,切换的时候要把页表给切换掉,而页表的切换开销是比较大的

  3. 由于同一进程的各线程间共享内存和文件资源,那么在线程之间数据传递的时候,就不需要经过内核了,这就使得线程之间的数据交互效率更高了

线程创建方式

  1. 继承Thread类重写run方法,好处是方便传参,可以通过set方法和构造函数传递参数。但由于Java是单继承,该类就不能再继承其他类;此外,任务和代码并未分离,当多个线程想要完成同一项任务时,需要创建多个线程类;任务没有返回值
class MyThread extends Thread {
    private String name;
    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name + ":" + Thread.currentThread().getId());
    }
}

class Main {
    public static void main(String[] args) {
        System.out.println("Main:" + Thread.currentThread().getId());
        Thread thread1 = new MyThread("1");
        Thread thread2 = new MyThread("2");
        thread1.start();
        thread2.run();
    }
}
  1. 实现Runnable接口run方法,实现了多个线程公用一个任务逻辑。不能添加成员变量,只能使用主线程里面被声明为final 的变量【这点可能是为了保证参数的线程安全,如果真的想用参数的话,只能用主线程里被final修饰的变量】。而且和Thread类一样,任务没有返回值
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getId());
    }
}
class Main {
    public static void main(String[] args) {
        System.out.println("Main:" + Thread.currentThread().getId());
        MyRunnable myThread = new MyRunnable();
        new Thread(myThread).start();
        new Thread(myThread).start();
    }
}
  1. FutureTask方式
class CallerTask implements Callable<String> {

    @Override
    public String call() throws Exception {
        return "hello";
    }
}



class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> futureTask = new FutureTask<>(new CallerTask());
        new Thread(futureTask).start();
        String s = futureTask.get();
        System.out.println(s);
    }
}

run()和start()方法区别

继承Thread类重写run方法实现线程创建,代码如下:

class MyThread extends Thread {
    private String name;
    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name + ":" + Thread.currentThread().getId());
    }
}

class Main {
    public static void main(String[] args) {
        System.out.println("Main:" + Thread.currentThread().getId());
        Thread thread1 = new MyThread("1");
        Thread thread2 = new MyThread("2");
        thread1.start();
        thread2.run();
    }
}

运行结果

Main:1
2:1
1:24

根据输出,可以分析出

1.run方法不会创建新线程,在主线程中调用run方法和调用普通方法没有区别

2.start方法启动一个新线程,但是从先输出的为thread2的run方法内容可以看出,start() 中的 run 代码可以不执行完就继续执行下面的代码,进行线程切换

3.start() 实现了多线程,run() 没有

还需要注意,一个线程被启动,你不能重复调用该thread对象的start方法,代码和执行结果如下:

class Main {
    public static void main(String[] args) {
        System.out.println("Main:" + Thread.currentThread().getId());
        Thread thread1 = new MyThread("1");
        thread1.start();
        Thread thread2 = new MyThread("2");
        thread2.run();
        thread1.start();
    }
}
Main:1
1:24
2:1
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.base/java.lang.Thread.start(Thread.java:791)
	at com.taotao.Main.main(SetModel.java:91)

总结:

run方法不会创建新线程,在主线程中调用run方法和调用普通方法没有区别

start方法启动一个新线程。通过start()方法来启动的新线程,处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行相应线程的run()方法,这里方法run()称为线程体,它包含了要执行的这个线程的内容,run方法运行结束,此线程随即终止。并且一个线程被启动,你不能重复调用该thread对象的start方法。

参考
小林Coding
Java并发编程之美

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值