Java创建多线程的四种方式

共 3827字,需浏览 8分钟

 ·

2020-09-27 09:25

点击上方蓝色字体,选择“标星公众号”

优质文章,第一时间送达

  作者 |  孤独患者的病态

来源 |  urlify.cn/N3Ifuy

66套java从入门到精通实战课程分享

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

什么是进程?

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

那什么是线程呢?

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

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

如何创建多线程?

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

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();

执行结果如下:

 ea5358cf8399f16f28d76876a322c222.webp 

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

二:实现Runnable接口创建线程

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

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

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

 执行结果如下: 

921f16a7799087a4bdae3e2aeed5eb36.webp

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

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

创建Callable对象

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

启动线程

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

执行结果如下:

ed968380b7e5631350aee8d572a64ec7.webp 

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

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

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

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


  • 创建一个可缓存的线程池,可以创建的范围是0-Integer.MAX_VALUE,当有可用线程时直接使用,当没有时创建新的线程并添加到缓存中,提供使用,这种类型的线程池,适合执行许多短期的异步任务的程序,是在执行方法之前创建线程,60秒内未使用的线程会被终止并删除缓存,

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue());
}
  • 创建一个单线程化的Executor,只会有一个线程池,当这个线程池挂掉会自动创建一个新的

public static ExecutorService newSingleThreadExecutor() {
       return new FinalizableDelegatedExecutorService
           (new ThreadPoolExecutor(1, 1,
                                   0L, TimeUnit.MILLISECONDS,
                                   new LinkedBlockingQueue()));
 }
  • 创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代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> future = threadPool.submit(new MyCallable());
            Map resultMap = future.get();
            System.out.println(resultMap);
        }
        threadPool.shutdown();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

执行结果如下:

b84ed53dc24a6f2385d994d817069390.webp

 

 


粉丝福利:108本java从入门到大神精选电子书领取

???

?长按上方锋哥微信二维码 2 秒备注「1234」即可获取资料以及可以进入java1234官方微信群



感谢点赞支持下哈 5b1f319c34e7c7c63ae2c9b7fa4da1da.webp



浏览 21
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报