Java创建线程的方法和区别

  • 1:继承Thread类创建线程

  • 2:实现Runnable接口创建线程

  • 3:使用Callable和FutureTask创建线程

  • 4:使用线程池,例如用Executor框架创建线程

继承Thread类创建线程

继承Thread类创建一个新的线程类,重写其run()方法

  • 因为java单继承的机制无法再继承其他的类

  • 直接使用this即可获得当前线程

  • 简单示例

public class ExtendThread {
    static class ThreadDemo extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println(getName() + "  -->  i");
            }
            System.out.println("End.....");
        }
    }

    public static void main(String[] args) {

        Thread thread = new ThreadDemo();
        thread.start();
    }
}

实现Runnable接口

观察Thread类的源码,发现Thread也是一个实现了Runnable接口的类。观察他的run()法,如果他的执行目标target不为空,则执行target的run方法。target是此类的一个实例对象,其类型是Runnable。在Thead中拥有可初始化此target的构造器。综上我们可以通过实现Runnable接口的方式,而后将实例传递给Thread从而实现线程的创建。

public class Thread implements Runnable

/* What will be run. */
private Runnable target;

public Thread(Runnable target) { ... }

@Override
public void run() {
    if (target != null) {
        target.run();
    }
}  

看一下Runnable接口的真面目:

@FunctionalInterface // 标示这是一个函数式接口:有且只有一个抽象方法,非必要的注解
public interface Runnable {
    public abstract void run();
}

Runnable是一个很简单的函数式接口,只有一个抽象方法,代表被执行的用户逻辑的抽象,此方法将在Thread中的target.run();被执行。

  • 简单示例
public class ByRunnable {
    static class ThreadDemo implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "  -->  i");

            }
        }
    }

    public static void main(String[] args) {

        new Thread(new ThreadDemo()).start();
        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "  -->  i");
            }
        }).start();

    }
}
  • 当使用此方法创建线程时,创建的类不是线程类而是线程类的目标类,需要将他交给线程类才能创建真正的线程。在访问线程时,需要通过Thread.currentThread()先获取到当前线程示例才能访问和控制当前线程

  • 好处是一方面他可以避免Java的单继承带来的局限性,另一方面也可以使逻辑和数据更好的分离

实现Callable接口

Callable接口位于java.util.concurrent包下:

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

他跟Runnable类似,也是一个函数式接口。不同的是他唯一的抽象对象是有返回值的,返回类型是接口的泛型,还有一个Exception的异常声明。在Thread中的target的类型是Runnable,并且这两个接口之间也没有任何的继承关系,显然我们不能使用Callable实例作为target直接创建线程了。为解决此问题,JDK我我们提供了一个中间桥接的接口:RunnableFuture

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

从上面代码可以出该接口继承了Runnable接口保证了其实例可作为Thread的目标类。同时继承了Future接口拥有了一些控制异步任务的功能,如取消执行中任务任务,判断异步任务是否完成以及获取异步任务执行结果等。

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

RunnableFuture既可以作为Thread的目标类,也可以获取异步任务的执行结果,作为Thread和Callable间一个重要的桥接角色。在创建对象时,需要使用到 RunnableFuture的一个实现类FutureTask.
在这里插入图片描述
Callable中的call()方法最终也是在Runnable的run()中被执行。

// FutureTask.java
public void run() {
   ...
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                // 在这里执行了Callable中的call()方法
                result = c.call();
                ran = true;
            } catch (Throwable ex) { ... }
            if (ran)
                set(result);
        }
    } finally { ... }
}

简单示例

public class ByCallable {

    public static final int COMPUTE_TIME = 1000000;

    static class ThreadDemo implements Callable<Long> {
        @Override
        public Long call() throws Exception {
            long startTime = System.currentTimeMillis();
            System.out.println(Thread.currentThread().getName() + " Started ...");
            Thread.sleep(1000);
            for (int i = 0; i < COMPUTE_TIME; i++) {
                int j = i * 10000;
            }

            long used = System.currentTimeMillis() - startTime;
            System.out.println(Thread.currentThread().getName() + " End ...");

            Thread.sleep(3000);
            return used;
        }
    }

    public static void main(String[] args) throws Exception {

        ThreadDemo task = new ThreadDemo();
        FutureTask<Long> futureTask = new FutureTask<>(task);
        Thread thread = new Thread(futureTask, "returnableThread");
        thread.start();
        Thread.sleep(500);
        System.out.println(Thread.currentThread().getName() + " 让子弹飞一会...");
        System.out.println(Thread.currentThread().getName() + " 做一点自己的事情...");
        for (int i = 0; i < COMPUTE_TIME; i++) {
            int j = i * 10000;
        }
        System.out.println(Thread.currentThread().getName() + " 获取并发任务的执行结果");
        try {
            System.out.println(thread.getName() + "线程占用时间:" + futureTask.get());
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + " 运行结束...");

    }
}

线程池技术

使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源开销,解决资源不足的问题。如果不使用线程池,有可能会造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。

public class ThreadPool {
    private static final int CORE_POOL_SIZE = 5;
    private static final int MAX_POOL_SIZE = 10;
    private static final int QUEUE_CAPACITY = 100;
    private static final Long KEEP_ALIVE_TIME = 1L;

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(QUEUE_CAPACITY),
                new ThreadPoolExecutor.CallerRunsPolicy());


        Future<Long> future = executor.submit(new Callable<Long>() {
            @Override
            public Long call() throws Exception {
                Thread.sleep(3000);
                System.out.println("异步任务开始。。。。");
                return 3L;
            }
        });

        Long result = future.get();
        System.out.println("异步任务结果:" + result);

        for (int i = 0; i < 5; i++) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 5; i++) {
                        System.out.println(Thread.currentThread().getName() + "  -->  i");
                    }
                }
            });
        }

        //终止线程池
        executor.shutdown();
        while (!executor.isTerminated()) {
        }
        System.out.println("Finished all threads");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值