Java创建多线程的四种方式
点击上方蓝色字体,选择“标星公众号”
优质文章,第一时间送达
作者 | 孤独患者的病态
来源 | urlify.cn/N3Ifuy
在进行讲解线程的创建方式之前,首先了解下什么是进程,什么是线程,进程与线程之间的关系等
什么是进程?
其实当一个程序进入内存运行时,就是一个进程,进程是处于运行中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位,具有独立性,动态性,并发性,这里的独立性指的是在系统中独立存在,有独立资源,有独立地址空间,没有进程允许,不会跟别的进程交互;动态性指的是进程在系统中有生命周期以及各种不同的状态,这也是跟程序的区别,进程加入了时间的概念;并发性指的是进程间可以在单处理器上并发执行,独立互不影响
那什么是线程呢?
多线程其实就是扩展了多进程的概念,使一个进程可以同时并发处理多个任务,可以看成是轻量级的进程;线程是进程的组成部分,一个进程可以有多个线程,线程可以有自己的堆栈,程序计数器,局部变量,但是没有系统资源,线程是必须有一个父进程的,他与父进程的其他线程是共享全部资源,线程的调度与管理是由父进程负责为完成
简单来说就是,操作系统可以同时执行多个任务,每个任务就是进程,进程可以同时执行多个任务,每个任务就是线程
如何创建多线程?
创建多线程的方式可以概括为四种:
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
启动线程
public static void main(String[] args) {
FutureTask
执行结果如下:
四:借助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
执行结果如下:
粉丝福利:108本java从入门到大神精选电子书领取
???
?长按上方锋哥微信二维码 2 秒备注「1234」即可获取资料以及可以进入java1234官方微信群
感谢点赞支持下哈