Runnable任务,用Thread或线程池启动它

178 阅读3分钟

定义任务的方式 Runnable接口

一个类只要实现了Runnable接口,将任务写在重写的run方法中,这就是定义了一个任务,看代码:

// Demo.java

//一个任务
static class RunnableDemo implements Runnable{
    @Override
    public void run() {
        System.out.println("hi");
    }
}

// main
public static void main(String[] args) {
    RunnableDemo runnableDemo = new RunnableDemo();
    runnableDemo.run();
}

定义了一个静态的RunnableDemo类,实现了Runnable接口,这样就将一个任务描述好了。

任务描述好了之后,需要将它交给线程去执行,这里是在main()的线程去调用的。

如果需要由单独的线程进行驱动,则需要Thread构造器。

Thread构造器,另起一个线程

Thread thread = new Thread(Runnable target);

我们只需要往里放一个Runnable对象即可,这是Thread其中一个构造函数。Runnable就是我们定义的任务。

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

所以使用Thread有两种方式:

  1. 事先用类实现Runnable接口定义任务
  2. 使用Thread构造器,采用匿名类的方式,在构造参数中使用lambda表达式 或者 匿名类的方式
Thread thread = new Thread(() -> {
    // 业务逻辑
});
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        // 业务逻辑
    }
});

Thread构造器的对象,调用其start()方法,为线程执行必需的初始化操作,然后会调用Runnable的run()方法。

忽略线程组

也许你在其他文章中或者Thread构造器中,看见了线程组的概念。这里引用Java编程思想中的一句话:“最好把线程组看成是一次不成功的尝试,你只要忽略它就好了”

接下去我们要了解一下新的管理线程的对象:Executor。

Executor 线程池

操作数据库连接的时候,如果手动管理一个连接需要手动的连接和关闭,这是需要很多开销时间的。这对并发管理线程是一样的道理,手动创建的Thread对象是没有线程池这个概念的,而且构造方式也表明了一个Thread对象只能操作一个任务。,所以Executor简化了并发编程。

线程池有哪些

引自博主

  1. newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  2. newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  3. newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
  4. newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

基本使用

通过Excetor.的方式就可以选择创建何种线程池,以newCachedThreadPool为例子;

创建对象后,调用execute,传入Runnable对象即可调用其执行方法。

执行结束后,记得关闭线程池,exec.shutdown()

public class CachedThreadPool{
    public static void main(String[] args){
        ExecutorService exec = Exectors.newCachedThreadPool();
        exec.execute(Runnable target);
        exec.shutdown();
    }
}

关闭线程池

  1. exec.shutdown():不再接受新任务,退出时会等待已经正在执行的任务。
  2. exec.shutdownNow: 停止所有正在执行的任务,不再接收新任务,并返回等待执行的任务列表。

那通常情况第一种关闭线程池的方法用的会多一点。