创建多线程的四种方式

在进行讲解线程的创建方式之前,首先了解下什么是进程,什么是线程,进程与线程之间的关系等

什么是进程?

其实当一个程序进入内存运行时,就是一个进程,进程是处于运行中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位,具有独立性,动态性,并发性,这里的独立性指的是在系统中独立存在,有独立资源,有独立地址空间,没有进程允许,不会跟别的进程交互;动态性指的是进程在系统中有生命周期以及各种不同的状态,这也是跟程序的区别,进程加入了时间的概念;并发性指的是进程间可以在单处理器上并发执行,独立互不影响

那什么是线程呢?

多线程其实就是扩展了多进程的概念,使一个进程可以同时并发处理多个任务,可以看成是轻量级的进程;线程是进程的组成部分,一个进程可以有多个线程,线程可以有自己的堆栈,程序计数器,局部变量,但是没有系统资源,线程是必须有一个父进程的,他与父进程的其他线程是共享全部资源,线程的调度与管理是由父进程负责为完成

简单来说就是,操作系统可以同时执行多个任务,每个任务就是进程,进程可以同时执行多个任务,每个任务就是线程

如何创建多线程?

创建多线程的方式可以概括为四种:

1,继承Thread类,重写run()方法

2,实现Runnable接口,重写run()方法

3,实现Callable接口, 重写call()方法,借助Future执行

4,借助Executor框架使用线程池创建线程

具体线程创建方式如下:

一:继承Thread类创建线程

class MyThead extends  Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + ": 继承Thread线程啦");
    }
}

调用线层的start()方法启动线程

 new MyThead().start();

执行结果如下:

 

 

 注:Thread其实也是实现了Runnable接口

二:实现Runnable接口创建线程

class MyRunnable implements  Runnable {
    public void run() {
        System.out.println(Thread.currentThread().getName() + ": 实现Runnable线程啦");
    }
}

  借助Thread类调用线层的start()方法启动线程

new Thread(new MyRunnable()) .start();

 执行结果如下: 

 

三:使用Callable和Future接口创建线程

Java5开始提供Callable接口,提供call方法作为线程的执行体,可以看成是Runnable接口的增强版本,增强点在于call()方法可以有返回值,并且可以抛出异常,由于Callable是新增的接口,不能作为Thread的target使用,所以Java5里提供了Future接口,该接口实现了Runnable,Future的实现类FutureTask类用来包装Callable对象,那么该怎么调用并获取返回值呢?下面用代码进行展示用法:

创建Callable对象

class MyCallable  implements Callable<Map<String, String>> {

    public Map<String, String> call() throws Exception {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("returnCode", "000000");
        map.put("messgae", Thread.currentThread().getName() + ":Callable创建线程成功");
        return map;
    }
}

 启动线程

public static void main(String[] args) {
        FutureTask<Map<String, String>>  future = new FutureTask(new MyCallable());
        new Thread(future).start();
        try {
            /**
             * get()返回Callable任务里的call()返回值
             * get方法是一个阻塞方法,对于task内置了一些任务状态,当任务状态为新建0或者初始化完成的时候1的时候会阻塞
             * 需要根据设置的时间阻塞,没有设置时会一直进行阻塞,一直到有结果返回
             */
            Map<String, String> resultMap = future.get();
            System.out.println(resultMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 

执行结果如下:

 

 

 

四:借助Executor框架使用线程池创建线程

  •  Executors提供了一系列工厂方法用于创先线程池,创建的线程池都实现了ExecutorService接口,下面为常用的线程池:

创建固定数目线程的线程池,操作一个共享的无边界队列,当所有线程都处于活动状态时,额外的任务被提交它们将在队列中等待,直到线程可用。当有线程池挂掉会重新创建一个新的

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
 }
 
  • 创建一个可缓存的线程池,可以创建的范围是0-Integer.MAX_VALUE,当有可用线程时直接使用,当没有时创建新的线程并添加到缓存中,提供使用,这种类型的线程池,适合执行许多短期的异步任务的程序,是在执行方法之前创建线程,60秒内未使用的线程会被终止并删除缓存,
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
}
 
  • 创建一个单线程化的Executor,只会有一个线程池,当这个线程池挂掉会自动创建一个新的
 public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
  }
  • 创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
 }
 
一般来说,CachedTheadPool在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程,因此它是合理的Executor的首选,只有当这种方式会引发问题时(比如需要大量长时间面向连接的线程时),才需要考虑用FixedThreadPool
 
下面提供一个固定大小的线程池的使用案例:
    public static void main(String[] args) {
        try {
            ExecutorService threadPool = Executors.newFixedThreadPool(10);
            for (int i = 0; i <15; i++) {
          //主要通过submit方法执行调用,可以接收Runnable,Callable Future<Map<String, String>> future = threadPool.submit(new MyCallable()); Map<String, String> resultMap = future.get(); System.out.println(resultMap); } threadPool.shutdown(); } catch (Exception e) { e.printStackTrace(); } }
 
执行结果如下:

 

 

下一篇再介绍相关线程的其他知识,欢迎讨论,一起学习

Tags: