JAVA多线程并发(简化版)(一)

JAVA并发系列文章(一)

`



前言

新手笔记,写来防止我的偷懒(内容如有出错,还望各位大佬多多指出)
`


提示:以下是本篇文章正文内容,下面案例可供参考

一、JAVA线程如何实现/创建?

1.线程是什么?(资源调度最小单位)

对计算机来说,一个任务就是一个进程,进程是资源分配的最小单位。但是进程是由一个或者多个线程(线程也叫轻量级进程)组成的,而线程是进程中的实际运行单位,是资源调度的最小单位。是独立于进程之中的子任务。Java中线程(Thread)以对象形式存在

举例子:
1.打游戏时,打开客户端的时候会启动很多线程,比如好友聊天线程,队列进程等。
2.main主函数相当于一个主线程,多线程就相当于在main函数执行时,同时运行其他的进程,这种情况下有可能造成线程之间的资源竞争等

2.线程实现/创建方式

1.继承Thread类(是Runable接口的一个实例)

 Public 一个继承Thread的类(内部写上运行方法)+new一个新对象+新对象.start()
 start():是一个native方法,会启动一个新线程,并执行run()方法

ps:
native方法是一个java调用非java代码的接口,这个方法是由非java语言实现的,比如c/c++(既然不是java写的,我们就不用去看源码了,知道已经是已经实现了的就可以了,是操作系统实现的,java只能调用)
——
这就是为什么java是跨平台的语言,既然跨平台了,就要牺牲一些对底层的控制,所以就要其他语言的帮助,native就是这个作用
——
run()方法是Runnable接口中定义的,而start()是Thread类定义的,所有实现Runable的接口的类都要重写run方法,run方法是默认绑定操作系统的,是线程执行的入口
——
run()和start()的区别可以用一句话概括:单独调用run()方法,是同步执行;通过start()调用run(),是异步执行。

2.实现Runnable接口
java不可以继承多个类,是单继承的,但是通过接口可以实现多继承(一个java类智能继承一个父类,但可以有多个接口)

步骤:
定义类(是否有继承)implements Runnable
重写Runable接口中的run方法
new一个我们刚刚定义的类
实例化一个Thread,并传入自己的实例,并用start()启动我们刚刚定义的类

3.ExecutorService+Callable+Future有返回值线程

有返回值的任务必须实现Callable接口,无返回值的任务必须Runnable接口。
执行了Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取Callable任务返回的Object,再加上ExecutorService(线程池接口)就可以实现有返回结果的多线程

在这里插入图片描述

4.基于线程池的方式

利用缓存的策略,不需要我们再去创建和销毁,这样可以节省资源

二、有哪几种线程池(可以手动/自动创建)?(4种)

线程池是什么?

java中经常需要用多线程来处理一些业务,不建议单纯使用继承Thread或者实现Runnable接口来创建线程,因为那样创建会引发创建/销毁线程耗费资源,线程上下文切换等问题,同时创建过多线程也可能导致资源耗尽。
因此引入了线程池,方便线程任务的管理。JDK1.5开始的java.util.concurrent包中,设计的几个核心类以及接口包括:Executor+Executors+ExecutorService+ThreadPoolExecutor+Callable+Runnable等

线程池作用

1.加快响应请求(时间优先)(为了缩短接口响应时间,往往不设置队列去缓存并发的请求,而是尽可能创造线程来执行任务,利用corePoolSize和maxPoolSize)
2.处理大任务速度快(吞吐量优先)(往往设置队列来缓存并发任务,避免corePoolSize和maxPoolSize设置参数太大,造成线程上下文频繁切换,降低了任务处理速度)

ThreadPoolExecutor(手动创建)

可以灵活设置线程池的各个参数,体现在ThreadPoolExecutor类构造器上各个实参的不同

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)


corePoolSize

核心线程数,线程池初始化时默认没有线程的,有任务了才开始创建线程去执行任务

maximumPoolSize

最大线程数,在核心线程数上可能会增加一些非核心线程,只有当workQueue队列满了才会创建多余corePoolSize线程(线程总数≤maxPoolSize)

keppAliveTime

非核心线程空闲时间超过keepAliveTime就会被自动终止回收

unit

keepAliveTime的时间单位

workQueue

用来保存任务的队列(池子里的任务数大于corePoolSize时,就会把新来的任务放进这里)

threadFactory

线程工厂,主要用来创建线程,默认用Executors.defaultThreadFactory(),也可以用guava库的ThreadFactoryBuilder来创建

handler(最好自己定义拒绝策略的方案,这4个方案是参考)

线程池拒绝处理任务时的策略(AbortPolicy,DiscardPolicy,DiscardOldestPolicy,CallerRunsPolicy)

AbortPolicy:丢弃任务并抛出异常
DiscardPolicy:丢弃任务但不抛出异常
DiscardOldPoilcy:丢弃队列最前边的任务,重新尝试执行任务(不断重复)
CallRunsPolicy:只要线程池不被关闭,就会在调用线程中,运行被丢弃的任务

Executors工具类中的四种线程池(自动创建)

1.newCachedThreadPool

只会重用空闲并且可用的线程,对于执行很多短期异步任务程序而言,这些线程池通常可提高程序性能。
线程可用(调用execute重用以前的线程)
线程不可用(创建一个新线程)
还会终止并从缓存里移除超过60秒没被使用的线程

2.newFixedThreadPool

采用队列(队列大小未被设置)缓存线程的模式,重点在可以按照自己需求定义核心线程池数量和最大线程数

3.newScheduledThreadPool

创建一个线程池,可以安排在给定延迟后运行命令或者定期执行

4.newSingleThreadExecutor

是一个特殊的newFixedThreadPool,只是固定了某些参数值的ThreadPoolExecutor,这个线程池可以在线程死后(或者发生异常)重新启动一个线程来替代原来的线程继续执行下去。

三、线程生命周期

什么是线程生命周期?

指的是线程进入运行状态后要经过的5个状态。
一般的操作系统是采用抢占式方式来让线程获得CPU资源,然后线程状态在这几个状态下不断切换

经过的5个状态

1.新建状态(NEW)
使用new关键字创建一个线程后,就要由JVM来分配内存,并初始化其成员变量

2.就绪状态(RUNNABLE)
线程调用了strat()方法后,JVM会为其创建方法调用栈程序计数器,等待调度运行

3.运行状态(RUNNING)
就绪的线程获得了CPU,开始执行run()方法

4.阻塞状态(BLOCKED)
线程因为某种原因放弃了CPU使用权,暂时停止运行,直到进入可运行状态。有三种阻塞情况
在这里插入图片描述

5.死亡(DEAD)
1.正常结束:线程正常结束
2.异常结束:线程抛出一个Excetpion或者Error
3.调用stop:直接调用stop()方法来结束线程(stop方法会强制停止一个正在运行的线程,无论此时线程是何种状态,在停止线程时需要自行指定线程退出逻辑,否则线程立即退出,不做任何清理操作,因此会造成数据不一致问题)(建议换成interrupt方法)

四、如何终止线程?

1.正常运行结束

2.使用退出标志退出线程
即在线程内部定义一个bool变量来判断是否结束当前的线程

3.Interrupt来结束线程
interrupt就是用来中断线程的。
interrupt可以用来设置线程打断标志,但是不会修改线程的运行状态。

public void interrupt()

isInterrupted()(会返回布尔值)来判断线程是否已经中断。

public boolean isInterrupted()

interrupted()是用来获取进程打断标志,同时会清除打断标志。

public static boolean interrupted()

4.stop方法来终止线程(线程不安全)

总结

`

以上就是Java多线程并发的线程池一部分内容,后续笔记会继续更新

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值