• java线程——三种创建线程的方式


    前言


    线程,英文Thread。在java中,创建线程的方式有三种:

    1、Thread

    2、Runnable

    3、Callable


    在详细介绍下这几种方式之前,我们先来看下Thread类和Runnable接口。


    Runnable接口

    接口中只有一个run()方法,等待实现类去实现。

    1. package java.lang;
    2. @FunctionalInterface
    3. public interface Runnable {
    4. public abstract void run();
    5. }



    Thread类

    该类实现了Runnable接口,也提供了很多其他的方法,如yield(),join()等

    1. package java.lang;
    2. public
    3. class Thread implements Runnable {
    4. //获取当前线程
    5. public static native Thread currentThread();
    6. public static native void yield();
    7. //一系列的构造函数
    8. public Thread(Runnable target, String name) {
    9. init(null, target, name, 0);
    10. }
    11. public Thread(ThreadGroup group, String name) {
    12. init(group, null, name, 0);
    13. }
    14. /*调用该方法时,jvm会调用run方法
    15. *Causes this thread to begin execution; the Java Virtual Machine
    16. * calls the run method of this thread.
    17. */
    18. public synchronized void start() {
    19. if (threadStatus != 0)
    20. throw new IllegalThreadStateException();
    21. group.add(this);
    22. boolean started = false;
    23. try {
    24. start0();
    25. started = true;
    26. } finally {
    27. try {
    28. if (!started) {
    29. group.threadStartFailed(this);
    30. }
    31. } catch (Throwable ignore) {
    32. }
    33. }
    34. }
    35. }


    一、实现Runnable接口

    1. public class i_Runnable {
    2. /**
    3. * 主线程main方法
    4. * @param args
    5. */
    6. public static void main(String[] args) {
    7. for (int i = 0; i < 100; i++) {
    8. System.out.println(Thread.currentThread().getName() + "====" + i);
    9. if (i == 20) {
    10. RunnableThreadTest rtt = new RunnableThreadTest();
    11. //子线程
    12. new Thread(rtt, "new Thread[1]====").start();
    13. //new Thread(rtt, "新线程2").start();
    14. }
    15. }
    16. }
    17. /**
    18. * RunnableThreadTest实现Runnable接口
    19. * @author YANG
    20. *
    21. */
    22. static class RunnableThreadTest implements Runnable {
    23. private int i;
    24. @Override
    25. public void run() {
    26. for (i = 0; i < 100; i++) {
    27. System.out.println(Thread.currentThread().getName() + " " + i);
    28. }
    29. }
    30. }
    31. }



    执行结果:

       



    注意: 

        ** 执行结果只截取了部分内容。

        ** 如果RunnableThreadTest类前不加static,会报错No enclosing instance of type i_Runnable is accessible. Must qualify the allocation with an enclosin。因为只有内部类修饰为静态时,才可以在静态类方法(main方法)中调用该类的成员变量和方法。



    二、继承Thread类

    1. public class a_Thread {
    2. public static void main(String[] args) {
    3. Runner1 r=new Runner1();
    4. r.start(); //已经有thread 不需要new,直接调用start即可。
    5. for (int i = 0; i < 100; i++) {
    6. System.out.println("main Thread:"+i);
    7. }
    8. }
    9. //Runner1继承Thread类,重写run方法
    10. static class Runner1 extends Thread{
    11. @Override
    12. public void run() {
    13. for (int i = 0; i < 100; i++) {
    14. System.out.println("Runner1:"+i);
    15. }
    16. }
    17. }
    18. }


    思考:能不能将上面的r.start(); 改为 r.run();

    分析:换成run()方法之后,就变成了普通的方法调用,只有一个主线程,没有子线程。

    执行结果:为了方便显示,我们将循环次数改为10。


    1. Runner1:0
    2. Runner1:1
    3. Runner1:2
    4. Runner1:3
    5. Runner1:4
    6. Runner1:5
    7. Runner1:6
    8. Runner1:7
    9. Runner1:8
    10. Runner1:9
    11. main Thread:0
    12. main Thread:1
    13. main Thread:2
    14. main Thread:3
    15. main Thread:4
    16. main Thread:5
    17. main Thread:6
    18. main Thread:7
    19. main Thread:8
    20. main Thread:9


    三、实现Callable接口

           前面两种方式是传统的线程技术中的内容,第三种方式Callable和Future是jdk1.5之后新增的。我们先来补充点东西,看看这种方式与之前的方式有什么联系。

    1. //实现Callable接口
    2. public class j_CallableTest implements Callable<String> {
    3. public static void main(String[] args) {
    4. j_CallableTest test=new j_CallableTest();
    5. FutureTask<String> ft=new FutureTask<>(test);
    6. for (int i = 0; i < 100; i++) {
    7. System.out.println(Thread.currentThread().getName()+" i的值为="+i);
    8. if(i==20){
    9. new Thread(ft,"子线程").start();
    10. }
    11. }
    12. }
    13. //重写call方法
    14. @Override
    15. public String call() throws Exception {
    16. int i = 0;
    17. String reString = "";
    18. for (; i < 100; i++) {
    19. reString = Thread.currentThread().getName() + " " + i;
    20. System.out.println(reString);
    21. }
    22. return reString;
    23. }
    24. }

          从上面可以看到,new Thread的方式还是用的public Thread(Runnable target, String name); 说明FutureTask也是Runnable类型的,他们之间的关系可以从下图中看出来。



    那么,使用Callable和Future的方式有什么特点呢?

    我们从他们的定义来看,Callable接口中只有一个方法,返回值为V。前两种方式都是返回void。

    1. @FunctionalInterface
    2. public interface Callable<V> {
    3. /**
    4. * Computes a result, or throws an exception if unable to do so.
    5. *
    6. * @return computed result
    7. * @throws Exception if unable to compute a result
    8. */
    9. V call() throws Exception;
    10. }


    小结:

           1、接口实现更灵活,java不支持多继承。在这方面,Runnable和Callable更有优势。

           2、返回值问题。Runnable和Thread都不能有返回值,但Callable可以,而且支持多种类型的数据。


           就这两点来看,新增的Callable和Future的实现方式优势十分明显啊。但是追到原理,其实这三种都可以归结为一种方式。


  • 相关阅读:
    hdu4971 流-最大权闭包
    hdu4971 流-最大权闭包
    hdu4950 打怪(简单题目)
    hdu4950 打怪(简单题目)
    hdu4941 map交换行列
    hdu4941 map交换行列
    hdu4966 最小树形图(最少辅导花费)
    hdu4966 最小树形图(最少辅导花费)
    hdu4965 巧用矩阵乘法结合律
    POJ 1077 && HDU 1043 Eight A*算法,bfs,康托展开,hash 难度:3
  • 原文地址:https://www.cnblogs.com/jpfss/p/9329976.html
Copyright © 2020-2023  润新知