Java多线程之创建线程(四)

方法一,直接使用 Thread
 //创建线程,建议创建线程的时候取一个名字
Thread t = new Thread("t1"){
    @Override
    public void run() {
        //执行的方法
        System.out.println("通过 new Thread() 方法创建线程");
    }
};
//设置名称
//t.setName("t1");
//启动线程
t.start();



方法二,使用 Runnable 配合 Thread

把【线程】和【任务】(要执行的代码)分开

  • Thread 代表线程
  • Runnable 可运行的任务(要执行的代码)
  Runnable runnable = new Runnable() {
      @Override
      public void run() {
          //要执行的任务
          System.out.println("runnable");
      }
  };
//创建线程对象 参数1 是任务对象,参数2 是线程名称
Thread t = new Thread(runnable, "t2");
//启动线程
t.start();

方法二用 lambda 简化

 Runnable runnable = () -> {
            //要执行的任务
            System.out.println("runnable");
        };
//创建线程对象 参数1 是任务对象,参数2 是线程名称
Thread t = new Thread(runnable, "t2");
//启动线程
t.start();
System.out.println("Hello World!");

这是因为 Runnable 方法用了 @FunctionalInterface( 函数接口 ),能够使用Lambda的依据是必须有相应的函数接口(函数接口,是指内部只有一个抽象方法的接口)。

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}



Thread 与 Runnable 的原理关系

源码分析

 public static void test1() {
        //创建线程对象 
        Thread t = new Thread("t1"){
            @Override
            public void run() {
                System.out.println("Thread");
            }
        };
        //启动线程
        t.start();
        
    }

    public static void test2() {
        Runnable runnable = () -> {
            //要执行的任务
            System.out.println("runnable");
        };
        //创建线程对象 参数1 是任务对象,参数2 是线程名称
        Thread t = new Thread(runnable, "t2");
        //启动线程
        t.start();
    }

test1()

直接创建了 Thread 的子类对象,重写了Thread 中的父类 run() 方法,所以最终执行的是 Thread 中的子类方法。

test2() 调用构造方法

public Thread(String name) {
        init(null, null, name, 0);
}

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
}

   private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {

....
//传进来的runnable 对象(target) 会赋值给 Thread 中的一个成员变量
    this.target = target;
}
    
    
    //而成员变量的引用处
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
    

所以 Runnable 走的是 Thread 自身的 run() 方法,只不过 Thread 会检查

如果你有传进来 Runnable 对象,则优先调用 Runnable 自己的 run() 方法。

但本质上 test1 和 test2 ,将来线程运行时,都走 Thread 对象中的 run 方法


#### 结论
  • test1 把线程和任务合并一起,而 test2 把线程与任务分开
  • 用 Runnable 容易与线程池等高级 API 配合
  • 用 Runnable 使得任务类脱离了 Thread 继承体系,更灵活,因为 Java 本身推荐组合优于继承的


方法三,使用 FutureTask 配合 Thread

FutureTask 能接收 Callable 类型的参数,用来处理有返回结果的情况

FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("futureTask...");
                Thread.sleep(2000);
                return 666;
            }
        });

        Thread t1 = new Thread(futureTask, "task");
        t1.start();
        System.out.println(futureTask.get());

从源码得知 FutureTask 实现了 RunnableFuture 而 RunnableFuture

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

// Future<V> 是为返回一个结果
  V get() throws InterruptedException, ExecutionException;


Callable 相比于 Runnabel 可以抛出异常

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;





参考文献:
关于Java Lambda表达式看这一篇就够了

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值