Java重拾系列(一)Java线程与线程池

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zxccxzzxz/article/details/61007093

Java中线程的几种使用方式:

Runnable

Runnable是一个接口,直接实现并在run方法中执行相应的任务。

private class MyRunnableTask implements Runnable {
    @Override
    public void run() {
      // running my task
      int index = 0;
      while (index < 10) {
        System.out.println("I'm the task " + (++index));
      }
    }
}

public void createRunnable() {
    MyRunnableTask runnableTask = new MyRunnableTask();
    runnableTask.run();
}

Thread 线程

普通线程创建和启动的方式,创建Thread的实例时将Runnable对象传入其中,start()启动线程即可:

public static void createThread() {
    Thread myThread = new Thread(new MyRunnableTask());
    myThread.start();
}

ThreadPool 线程池

Executor

public interface Executor  {
    void execute(Runnable command);
}

Executor是用于代替显示的Thread创建,ExecutorService是拥有服务生命周期的Executor(例如shutDown / terminal等),ExecutorService需要通过Executors使用工厂方法来进行创建:

public void createExecutor() {
    ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.execute(new MyRunnableTask());
}

Executors

Executor的工厂方法工具集,提供了各类ThreadPool的创建方法。注意创建的都是ExecutorService类型的对象。如下所示创建一个含有固定线程数的线程池,nThreads代表线程数量。更多方法可以查阅Executors.java文件。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

ExecutorService

public interface ExecutorService extends Executor 

ExecutorService继承自Executor,提供了更多的生命周期相关的方法,例如:

  • void shutdown()
  • <T> Future<T> submit(Callable<T> task)
  • <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException
  • 省略…

源码注释中提供了Usage Examples:

 class NetworkService implements Runnable {
   private final ServerSocket serverSocket;
   private final ExecutorService pool;

   public NetworkService(int port, int poolSize)
       throws IOException {
     serverSocket = new ServerSocket(port);
     pool = Executors.newFixedThreadPool(poolSize);
   }

   public void run() { // run the service
     try {
       for (;;) {
         pool.execute(new Handler(serverSocket.accept()));
       }
     } catch (IOException ex) {
       pool.shutdown();
     }
   }
 }

 class Handler implements Runnable {
   private final Socket socket;
   Handler(Socket socket) { this.socket = socket; }
   public void run() {
     // read and service request on socket
   }
 }

以上代码可以看到,主要分为三个部分

  1. 构造函数的初始化,建立了一个Socket对象,同时创建了一个固定线程数的线程池实例。
  2. 内部类Handler实现了Runnable方法,通过Socket进行相应的服务请求与读取
  3. run()方法中循环执行了Handler的任务

这就是线程池相应的使用。简单来说其实线程池只是由于Thread的种种不便应运而生的一种线程处理机制,没有想象的那么复杂与麻烦。并且相对的比起Thread的普通创建方式来说,线程池能够节省资源开销,更合理和优雅的管理线程的状态。

Java通过Executor提供四种线程池:

  • CachedThreadPool : 将为每个任务都创建一个线程

  • FixedThreadPool : 预先执行代价高昂的线程分配,限制线程数量。优点是节省时间(创建线程需要开销)。直接从池中获取线程

  • SingleThreadExecutor : 以FIFO的入队方式处理任务。在第一个任务处理完之前第二个任务出于等待状态

  • ScheduledThreadPool : 能够延迟、周期性的执行任务,可以用于替换Timer

线程池优点:

  • 在任何线程池中,现有的线程都可能被自动复用(线程池的优点之一就是资源复用)
  • 减少new Thread()的性能开销,每次使用线程都伴随Thread的创建和销毁开销,性能很差
  • 上面我们可以看到创建时能够指定线程的并发数量,也就是说,我们能够对线程进行有效的管理,普通创建线程只好待其自我执行、销毁,并且执行的时间点我们也无法得知,而这些事情通过线程池我们都能做到

我们同样使用线程池来进行之前的循环打印,注意使用Executors和ExecutorService需要将其进行包的导入,两者都属于java.util.concurrent路径下:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadDemo {
    private static class MyRunnableTask implements Runnable {
        @Override
        public void run() {
            int index = 0;
            while (index < 10) {
                System.out.println("I'm the task " + (++index));
            }
        }
    }

    public static void createRunnable() {
        MyRunnableTask runnableTask = new MyRunnableTask();
        runnableTask.run();
    }
    public static void createThread() {
        Thread myThread = new Thread(new MyRunnableTask());
        myThread.start();
    }

    public static void createThreadPool() {
            ExecutorService exec = Executors.newCachedThreadPool();
            exec.execute(new MyRunnableTask());
    }

    public static void main(String[] args) {
        // createThread();
        // createRunnable();
        createThreadPool();
    }
}

三种方式都可以打印出相应的结果:

➜ ~ javac ThreadDemo.java
➜ ~ java ThreadDemo
I'm the task 1
I'm the task 2
I'm the task 3
I'm the task 4
I'm the task 5
I'm the task 6
I'm the task 7
I'm the task 8
I'm the task 9
I'm the task 10

猜你喜欢

转载自blog.csdn.net/zxccxzzxz/article/details/61007093
今日推荐