多线程和线程池的基本知识总结

1.多线程相关的三组概念:
1.程序和进程
1.进程(process):
进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。程序是指令、数据及其组织形式的描述,进程是程序的实体。
广义定义:是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
2.程序(program):
通常来说:计算机程序是一组计算机能识别和执行的指令,运行于电子计算机上,满足人们某种需求的信息化工具。
2.进程和线程
1.线程(thread):
是操作系统能够进行运算调度的最小单位,他被包含在进程之中,是进程中的实际运作单位。
2.线程和进程之间的区别:
根本区别:
进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位。
开销方面:
进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看作轻量级的进程,同一类线程共享代码和数据空间。
所处环境:
在操作系统中能同时运行多个进程(程序),而在同一个进程中有多个线程同时执行(通过cou调度,在每个时间片中只有一个线程执行)
内存分配方面:
系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。
包含关系:
没有线程的进程可以看作是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条 线程共同完成的;线程是进程的一部分,所以线程也被成为轻权进程或者轻量级进程。
3.进程和线程的关系:
进程包含线程;线程是进程的成员
3.并行和并发
1.并行:
同一时刻多个事件同时发生互不干扰的运行方式。永远不会发生交叉。
2.并发:
同一时刻运行多个事件同时发起,但是不同时执行【强调的是同一段时间内多个事件交替执行的方式】
4.CPU的调度:
分时调度:
根据要执行的程序的个数,安排合适的分配执行机制进行执行。
抢占式调度:
CPU随机的来执行程序,到每次执行那个程序CPU说了算。Java的jvm的CPU调度使用的就是抢占式调度

**2.问题:**既然只有一个cpu,还需要再不同的任务之间来回切换,那么CPU效率到底是提升了还是降低了?
1.从整体来说效率提升,对单个程序来说执行效率是下降的。
2.不同的设备之间速率的问题:
CPU:10^-9秒/次
内存:10^-6秒/次
磁盘:10^-3秒/次
人:10^秒
3.通过各个设备的运行速率可以知道,CPU的效率太高,价格昂贵,CPU执行程序的时候等其他的硬件执行,比较浪费资源,所以要采用抢占式调度,达到效率最大化

3.多线程的实现方式
构造方法:
Thread():
创建一个默认名称的线程对象,没有线程任务
Thread(String name):
创建一个线程名称为name的线程对象
Thread(Runnable r):
创建一个线程名称为name的线程对象,没有线程任务
Thread(Runnable r,String name):
创建一个线程名称为name并以r为执行任务的线程对象
常用方法:
run():
封装线程要做的任务
Start():
开启线程并通知JVM调用run方法执行该线程的任务
1.方式一:【继承Thread类】是用来描述线程的特征和行为的类。一个对象就相当于一条线程。
步骤:
1.创建类继承Thread类【继承run方法将来重写】
2.重写run方法【重写指定该线程的任务】
3.new线程对象调用start()方法启动线程执行run方法
4.成员变量要加上private static final修饰让其属于类
2.方式二:【实现Runnable类】
步骤:
1.创建类实现Runnable接口【类的对象叫做线程任务对象】
2.重写run方法:指定线程任务
3.利用Thread(Runnable r):构造方法创建线程对象【绑定任务对象和线程对象一起】
4.启动线程【调用start()方法】
Runnable :是一个接口,里面有且只有一个run方法,它的实现类必须重写run方法,接口存在的意义就是来指定线程人物的。但是这里指定的任务和线程没有关系。利用Thread(Runable r)构造方法让任务和线程产生关系。

4.使用匿名内部类创建线程对象:
问题1:什么是匿名内部类?没有名字的子类对象
本质:是一个对象;没有对象名
使用前提:
1.必须有继承或实现关系
2.一定有重写方法格式:new 父类或接口名(){重写的方法};

5.Thread类中的常用方法:
1.获取线程名称:
getName():获取线程名称【普通方法,被线程对象调用】;;;;{线程可以人为命名的}
2.设置线程名称
setName(String name):给线程改名
结论:
1.线程没有指定名称的时候,默认名称是以thread开头后面根数字从0开始一次递增1
线程可以指定名称,可以构造指定也可以是set方法指定,可以重名
3.获取当前线程对象:
1.作用:可以再任意的位置,获取当前正在执行这段代码的线程对象。
2.静态方法:
Thread Thread.currentThread();返回当前正在执行这段代码的线程对象的引用,那条线程再执行这段代码,返回的就是那条线程的对象
4.线程休眠:
1.Thread.sleep(Long time):
使开启的线程休眠time常时间。以毫秒为单位;是一个静态方法
注意事项:
sleep方法存在一个interruptedException异常。该异常再main方法中可以声明处理也可以捕获处理
如果再run方法中,InterruptedException异常,只能捕获异常处理
5.守护线程
概述:
给普通线程执行创造执行环境的线程,守护普通线程可以安全的执行。一般守护线程看不到的。比如:垃圾回收线程
如果所有的普通线程都消失,守护线程就没有存在的必要。【普通线程消失,守护线程也会及时的关闭】
方法:
1.setDaemon(boolean flag):给线程设置成为守护线程
2.isDaemon():判断该线程是否为守护线程
6.线程优先级
概述:
1.jvm对线程的执行采用的是抢占式调度,线程的执行顺序没法控制,但是有的时候对于一些特殊的县城要求提前执行情况,想办法认为的控制一下执行顺序,给线程增加了优先级的概念
2.优先级数值越大优先级越靠前。
设置优先级的方法:
setPriority(int new Priority):更改线程的优先级。线程的默认优先级是5
thread类中有三个优先级的常量值:
MAX_PRIOITY:线程可以具有最高优先级10
MIN_PRIORITY:线程可以具有的最低优先级
NORM_PRIORITY:分配给现成的默认优先级。5

6.多线程中的线程安全问题
概述:
两个线程操作同一个对象的资源,导致俩个线程都再同时执行请求同一个资源
原因:
同一个对象的资源被两个不同的线程执行使用,线程执行机制是抢占式调度,执行时jvm两个线程之间来回切换,出现一个线程方法还没有执行完毕,就去执行另一个线程,导致俩个线程到的一部分内容出席那问题
多线程问题的产生就是多个线程使用同一个资源产生的。
解决方法:
因为线程未执行完毕目前做的事,所以要把一段事情全部做完之后再去做别的事情,所以要给jvm执行的代码加上约束【锁】
加锁的方式:
同步代码块
同步方法
同步代码块:
作用:解决多线程安全问题的
使用格式:
synchronized(锁对象){会发生线程安全的代码}
同步代码块上锁:上在资源有可能产生问题的代码上
同步方法:
概述:
把线程要执行的代码使用方法封装起来,然后我给方法上把锁,将来jvm要想执行这个方法,必须有这个方法对应锁
同步方法的格式:
权限修饰符 synchronizied 返回值类型 方法名称(参数列表){【需要同步的方法体;;多条线程共同执行的代码段】}
锁对象的说明:
问题1:同步代码块的锁对象是谁?
1.同步代码块的锁对象没有确定前可以是任意引用数据类型对象,一旦确定下来,所有的同步代码块的锁对象保证唯一【锁唯一,不然解决不了安全问题】
2.普通同步方法:默认的锁对象是this【当前调用对象】
3.静态同步方法:默认的锁对象是字节码文件对象【类名.class】
使用注意事项【保证锁对象唯一】:
如果单一方式使用:
1.单一同步代码块:需要同步代码块的所有的锁对象上下一致,保证唯一
2.单一使用同步方法:需要保证所有的同步方法调用的对象始终是一个对象
混合使用:
1.普通同步方法和静态同步方法不能够混用【锁对象不唯一】
2.同步代码块和同步方法混用:保证同步代码块的锁对象和同步方法的锁对象保持一致
死锁
1.概述
A线程需要甲资源,同时拥有乙资源才能继续执行【甲乙资源合起来是锁资源】;B线程需要乙资源,同时拥有甲资源才能继续,两条线程都不肯释放自己拥有的资源,同时也需要对方的其他的资源时,都无法进行,形成“死锁”现象
2.代码表现:
有了同步代码块的嵌套,就可能发生死锁。某条线程获取了外层的锁对象A,需要内层的锁对象B,等待;另外一条线程获取了外层的锁对象B,需要内层的锁对象A,等待,两条线程形成死锁

7.线程的等待唤醒机制【线程的通信机制】
概述:
就是线程和线程之间的相互沟通的通信 手段
OBject的通信方法:
wait():锁对象要线程无限等待
wait(long time):要线程等待time时长
notifyAll():唤醒监控的【锁对象】等待的所有线程
notify():唤醒监控的【锁对象】等待的单条线程【线程有了执行资格】

8.线程的生命周期
概述:
一条线程从创建到消亡的过程。在这个周期中线程对应的会有不同的状态。不同的状态有不同的特征
生命周期:
1.新建:创建线程对象
2.就绪:拥有执行资格,没有执行权【start方法启动了但是jvm没有执行】
3.运行:拥有了执行资格,有执行权力【start方法启动了,同时jvm也赋予执行权力】
4.阻塞:没有执行资格,没有执行权力【被sleep wait】等方法阻塞了
5.死亡:线程对象变成垃圾,等待回收【run方法执行完毕了】
线程状态:
NEW:【新建】:新建时期
RUNNABLE【运行】:对应的是就绪和运行两个时期
BLOCKED【锁阻塞】:线程再运行的时候遇到了锁,没有锁对象等待jvm
WAITING【无限等待】:线程运行的时候,被锁对象制止了,不被唤醒不能执行
TIMED_WAITING【计时等待】:线程运行的时候,被锁对象制止了一段时间
TERMINATED【死亡】:死亡时期
获取线程状态的方法:
getState():获取线程的状态值

9.线程池
概述:存放线程对象的容器。有大小,可控的,存放的线程对象都是没有任务线程对象
好处:
1.线程对象统一管理增加了维护性
2.减少了资源的浪费,提高了效率
3.解放开发工作者,提升开发效率
使用:
获取线程池对象:
使用工具类:Executors
1.新建一个线程池:
Executors.newFIxedThreadpool(int nThreads); 参数nThreads:指定线程池的大小【线程对象的个数】
2.常用方法:
1.提交执行线程任务:submit(Runnable runnable)
2.关闭线程池:
shutdown():所有提交的任务运行完再关闭线程池
shutdownNow():把正在运行的提交任务运行完立即关闭线程池
线程池的使用步骤:
1.获取线程池对象【相当于获取到了线程对象】
2.实现Runnable接口重写run方法【定义任务对象】
3.提交任务对象给线程池【调用submit方法提交任务】
4.关闭线程池
注意事项:
线程池里面 存放的都是没有任务的线程对象,只需要提供任务对象到线程池即可,使用线程池只需要使用实现接口方式准备线程任务即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值