线程与线程池

线程与线程池

 

什么是线程,

 

提到线程就要说一下进程,

 

进程:  进程就是正在执行的程序,(任务管理器)

 

线程: 是程序执行的一条路径,一个进程中可以包含多条线程,

 

举个例子,你打开你的微信,这叫打开了一个进程,你在微信里跟微信好友视频聊天就是开启了一个线程,

 

两者之间的关系
一个进程中至少有一个线程,当然也可以有多条线程

一条线程一定会在进程里面

 

线程的5种状态:

 

 

新生状态(New): 当一个线程的实例被创建(new)后,此时该线程处于新生(new)状态,处于新生状态的线程有自己的内存空间,但该线程并没有运行,此时线程还不是活着的(not alive)。
就绪状态(Runnable): 通过调用线程实例的start()方法来启动线程使线程进入就绪状态(runnable);处于就绪状态的线程已经具备了运行条件,在系统为其分配CPU之后才会执行;若线程未被分配到CPU的话不会执行,就绪状态并不是运行状态;此时线程是活着的(alive)。
运行状态(Running): 一旦获取CPU(被JVM选中),线程就进入运行(running)状态,线程的run()方法才开始被执行;在运行状态的线程会执行自己的run()方法中的操作,直到调用其他的方法而终止、或者等待某种资源而阻塞、或者完成任务而死亡;如果在给定的时间片内没有执行结束,就会被系统给换下来回到线程的等待状态;此时线程是活着的(alive);
阻塞状态(Blocked):通过调用join()、sleep()、wait()或者资源被占用使线程处于阻塞(blocked)状态;处于Blocking状态的线程仍然是活着的(alive)
死亡状态(Dead):当一个线程的run()方法运行完毕或被中断或被异常退出,该线程到达死亡(dead)状态。此时可能仍然存在一个该Thread的实例对象,但该Thread已经不可能在被作为一个可被独立执行的线程对待了,线程的独立的call stack已经被dissolved。一旦某一线程进入Dead状态,他就再也不能进入一个独立线程的生命周期了。对于一个处于Dead状态的线程调用start()方法,会出现一个运行期(runtime exception)的异常;处于Dead状态的线程不是活着的(not alive)。

 

 

 

 

创建线程的三种方式

第一种:

1定义一个类继承Thread,并重写Run方法

2将要执行的代码写到Run方法中,

3创建这个类的实例,得到对象调用start方法,开始这个条线程

 

 

第二种:

  1. 定义一个类MyRunnable实现Runnable接口,并重写run方法。
    2、将要执行的代码写在run方法中。
    3、创建Thread对象, 传入MyRunnable的实例,并调用start()方法开启线程。

 

 

 

 

 

 

 

 

第三种:

 

  1. 自定义一个类 MyCallable 实现 Callable 接口,并重写call()方法
    2、将要执行的代码写在call()方法中
    3、创建线程池对象,调用submit()方法执行MyCallable任务,并返回Future对象
    4、调用Future对象的get()方法获取call()方法执行完后的值

 

 

 

创建线程的三种方式对比

一、继承 Thread 类与实现 Runnable 接口的区别

我们都知道java支持单继承,多实现。实现 Runnable 接口还可以继承其他类,而使用继承 Thread 就不能继承其他类了。所以当你想创建一个线程又希望继承其他类的时候就该选择实现 Runnable 接口的方式。

二、实现 Callable 接口与 Runnable 接口的区别

Callable 执行的方法是 call() ,而 Runnable 执行的方法是 run()。
call() 方法有返回值还能抛出异常, run() 方法则没有没有返回值,也不能抛出异常。

 

 

多线程

一个进程中有N个线程,

 

 

多线程的优点,为什么要实现多线程

 

  1. 提高CPU的使用率
    例如朋友圈发表图片,当你上传9张图片的时候,如果开启一个线程用同步的方式一张张上传图片,假设每次上传图片的线程只占用了CPU 1%的资源,剩下的99%资源就浪费了。但是如果你开启9个线程同时上传图片,CPU就可以使用9%的资源了。
    2、提高程序的工作效率
    还是拿朋友圈发表图片来说,假设开启一个线程上传一张图片的时间是1秒,那么同步的方式上传9张就需要9秒,但是你开启9个线程同时上传图片,那么就只需要1秒就完成了。

 

缺点 会影响CPU的性能,因为CPU需要在线程之间来回切换,还会出现线程安全的问题(死锁)

 

多线程中的并行与并发

概念:

并行:多个处理器或者多核处理器同时执行多个不同的任务。一台手机上开了好几个App,这是并行
并发:一个处理器处理多个任务。

比如 双十一,6.18,下单

 

 

为什么多线程会出现线程安全的问题:

 

原因是有多个线程在操作共享的数据。即一个线程在操作共享数据的过程中CPU切换到其他线程又对该数据进行操作,这就是所谓的多线程并发。

 

解决办法:

把操作数据的那段代码用synchronized 进行同步, 这样就能保证在同一时刻只能有一个线程能够访问。

 

举例子:开两个线程上传照片,下面上代码:

 

 

 

 

如果不加上图中红圈中的同步锁就会出现线程安全的问题,synchronized 是用来保证共享资源同步的,

 

下图是出现线程安全问题的打印结果.

 

 

 

 

 

线程池

 

 

什么是线程池,为什么要有线程池,他有什么优点

 

为了提高工作效率,提高CPU的使用率,我们有的时候会创建多个线程去完成任务,但是线程

的创建和销毁是非常消耗CPU和内存的,因为他涉及到与操作系统的交互,这样性价比太低,

导致创建与销毁线程的消耗比你实际要完成的业务还大,那么就出现了线程池,在线程池中

的线程每一条线程结束后,并不会被销毁,而是回到线程池中成为空闲等待状态,等到下一个

对象来使用,

 

所以一句话总结线程池,他减少了创建和销毁线程带来的性能开销,还可以控制最大并发线程的数量,避免出现对内存的过多消耗

 

线程池是存在于内存的堆中

 

主要了解一下java.uitl.concurrent.ThreadPoolExecutor(思瑞得,扑哦,伊克塞Q他)类,是线程池中最核心的一个类,

 

 

 

 

CorePoolSize 
线程池的核心线程数

默认情况下,核心线程数会在线程中一直存活,即使它们处于闲置状态。

 

maximumPoolSize 
线程池所能容纳的最大线程数。

当活动线程数达到这个数值后,后续的新任务将会被阻塞。

 

keepAliveTime 
非核心线程闲置时的超时时长,超过这个时长,非核心线程就会被回收,当ThreadPoolExector的allowCoreThreadTimeOut属性设置为True时,keepAliveTime同样会作用于核心线程。

 

 

 

unit 
用于指定keepAliveTime参数的时间单位,这是一个枚举,常用的有TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)以及TimeUnit.MINUTES(分钟)等。

 

TimeUnit.NANOSECONDS  纳秒

TimeUnit.MICROSECONDS 微秒

TimeUnit.MILLISECONDS 毫秒

TimeUnit.SECONDS    秒

TimeUnit.MINUTES    分钟

TimeUnit.HOURS      小时

TimeUnit.DAYS       天

 

 

workQueue 
线程池中的任务队列,通过线程池execute方法提交的Runnable对象会存储在这个参数中。

这个任务队列是BlockQueue类型,属于阻塞队列,就是当队列为空的时候,此时取出任务的操作会被阻塞,等待任务加入队列中不为空的时候,才能进行取出操作,而在满队列的时候,添加操作同样被阻塞。

 

核心方法:

execute() 执行

submit() 提交

shutdown()

shutdownNow() 关闭

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值