JAVA多线程笔记整理

第四章第五节 多线程

多线程技术概述
线程与进程
1、进程 :(可简单理解为软件。)
是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间
2、线程 :(可简单理解为软件中的执行路径。)
(1)是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行. 一个进程最少 有一个线程
(2)线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分成若干个线程
线程调度
1、分时调度
所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
2、抢占式调度
(1)优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性), Java使用的为抢占式调度
(2)CPU使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核新而言,某个时刻, 只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是 在同一时 刻运行。 其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的 使 用率更高。
同步与异步
1、同步:排队执行 , 效率低但是安全.
2、异步:同时执行 , 效率高但是数据不安全.
并发与并行
1、并发:指两个或多个事件在同一个时间段内发生。
2、并行:指两个或多个事件在同一时刻发生(同时发生)。
继承Thread
Thread:Java提供的用于实现多线程的类
1、如果想要开启一个新的执行路径,需要继承thread(仅为一种实现方式,还有其他方式)
2、需要重写run方法(线程要执行的任务方法)。
3、在mian方法中,通过thread对象的start()方法启动,详见下图
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
注意:1、每个线程都拥有自己的栈空间,共用一份堆内存
2、由一个线程所调用的方法,也会执行在这个线程里面
Thread优点:可以通过匿名内部类的方式编辑,更加便捷
在这里插入图片描述
上图说明:创建了一个类,没有起名。指定父类为thread。并且创建了对象,仅调用一次start方法。
实现Runnable
实现Runnable与继承thread相比有如下优势:
1、通过创建任务,然后给线程分配的方式来实现多线程,更适合多个线程同时执行相同任务的情况。
2、可以避免单继承所带来的局限性。
3、任务和线程本身是分离的,提高了程序的健壮性。
4、后续学习的线程池技术,接受runnable类型的任务,不接受thread类型的线程。
Runnable:Java提供的用于实现多线程的接口
1、如果想要开启一个新的执行路径,需要实现接口Runnable(仅为一种实现方式,还有其他方式)
2、需要重写run方法(线程要执行的任务方法)。
3、在mian方法中:
(1)创建一个任务对象。
(2)创建一个线程,并为其分配任务。
(3)执行这个线程,通过start()方法。
在这里插入图片描述在这里插入图片描述

Thread类
详见jdk常用方法
设置和获取线程名称
在这里插入图片描述在这里插入图片描述

Getname:返回此线程的名称。
CurrentThread:返回对当前正在执行的线程对象的引用。
线程休眠sleep
Thread.sleep(毫秒)、Thread.sleep(毫秒,纳秒):休眠
1000毫秒=1秒

线程阻塞
可简单理解为比较消耗时间的操作,例如:
线程休眠、线程执行中读取文件耗时、接收用户输入等
线程的中断
一个线程是一个独立的执行路径,它是否应该结束,应由其自身决定
中断方式:给线程打入中断标记(interrupt),触发异常try-catch,程序员在程序块catch里面进行编辑如何关闭(return)或者不进行关闭
案例:主线程(main)执行完毕后,将t1线程中断
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

守护线程
线程:分为守护线程和用户线程。
守护线程:守护用户线程的,当最后一个用户进程结束时,所有守护线程自动死亡。
用户线程:当一个线程不包含任何的存活的用户线程时,进程结束。
在这里插入图片描述

案例解析:主线程打印1到5,T1线程打印1到10,如果把T1设置(setDaemon方法)为守护线程。那么主线程打印结束后,T1线程也会结束,不会打印后续结果。
线程不安全问题
多线程操作同一个变量时,会出现安全问题。
在这里插入图片描述在这里插入图片描述

解析:三个进程同时处理同一变量count,因为时多进程,当仅剩下最后一张票时,有可能三者同时进入while循环中,所以产生错误。
线程安全1-同步代码块
同步代码块(简单理解为括号内内容会排队)格式:
Synchronized(锁对象){ }
前提:()内需要传参,传的是锁对象(任何对象都可以当作锁存在,任何对象都能传)
注意(模糊点):若是一百个对象,要看一把锁,才能实现排队的效果。
在这里插入图片描述在这里插入图片描述

线程安全2-同步方法
在这里插入图片描述在这里插入图片描述在这里插入图片描述

上图中,Sale()方法中锁是this(原因:不是静态修饰),如果是静态修饰时,锁就是Ticket.class(格式:类名.class)
注意:如果一个类里面有十个同步方法,用的都是同一把锁this,若其中一个方法执行,其他方法无法执行。
同步代码块锁了一段代码,同步方法又锁了一段代码,两者使用了同一个锁对象this。若其中一个执行,另一个无法执行。
线程安全3-显式锁Lock
同步代码块和同步方法时隐式锁
显式锁比隐式锁更好一些,更体现了面向对象的机制。
显式锁Lock 子类 ReetrantLock

在这里插入图片描述

公平锁与非公平锁
公平锁:先来先到,排队 非公平锁:大家一块抢
在这里插入图片描述

示例:创建锁时fair参数传入ture为公平锁,如下图
线程死锁(大家一块抢)

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

罪犯在等待警察执行完c方法以后,调用警察的fun方法(回应方法)
警察在等待罪犯执行完c方法以后,调用罪犯的fun方法(回应方法)
两个人都是卡在这,呈现死锁的情况
解决方案:在任何有可能导致锁产生的方法里,不要再调用另外一个方法,让另外一个锁产生。
多线程通信问题
用到object类常用方法:详见jdk常用方法-object
案例:a线程通过对象haha睡着了,其他线程想要唤醒a线程,那么需要调用haha对象的notify()或者notifyAll()
详情可见生产者和消费者问题,代码详见文档。
线程的六种状态
在这里插入图片描述在这里插入图片描述

带返回值的线程Callable(用的较少)
特殊的创建线程的方法:Callable更像是主线程指派给了一个任务,执行完毕后会有一个结果,主线程可以拿到。
Thread和Runnabie是和主线程一块执行的,两个人一块走。
Callable可以实现和主线程一起执行,也可以实现让主线程等待子线程执行完毕,给主线程结果。(有了主和次的感觉)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

打印结果(因为加了get方法):
1、先打印下面(子线程)的0123456789
2、再打印返回值100
3、再打印主线程0123456789
task.get():返回一个值
task.isDone():用于判断子线程是否执行完毕
task.cancel():用于取消子线程执行(有参数,时布尔类型的,传入ture表示取消,也有一个布尔类型的返回值表示是否成功)
线程池概述
1.缓存线程池(长度不限制,任务并发时执行)
执行流程: 1. 判断线程池是否存在空闲线程
2. 存在则使用
3. 不存在,则创建线程 并放入线程池, 然后使用
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

ExecutorService:对象类型
Executors.newCachedThteadPool():创建缓存线程池
service.execute():执行新的任务,需要传入Runnable对象
2.定长线程池(长度时指定的数值,任务并发时执行)
执行流程:

    1. 判断线程池是否存在空闲线程
    1. 存在则使用
    1. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
    1. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
      在这里插入图片描述

Executors.newFixedThteadPool():创建定长线程池,并传参数,给定指定的长度
3.单线程线程池 (效果与定长线程池 创建时传入数值1 效果一致.)
假设有些任务需要子线程去执行,并且要求排队执行,那么可以使用单线程来执行这些任务。
执行流程:

    1. 判断线程池 的那个线程 是否空闲
    1. 空闲则使用
    1. 不空闲,则等待 池中的单个线程空闲后 使用

在这里插入图片描述在这里插入图片描述

Executors.newSingleThreadExecutor():创建单线程线程池
4.周期性任务定长线程池
【定时执行(当某个时机触发时, 自动执行某任务)、定时间隔周期重复执行】
任务创建出来的结果不一样

  • 执行流程:
    1. 判断线程池是否存在空闲线程
    1. 存在则使用
    1. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
    1. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
      在这里插入图片描述在这里插入图片描述

ScheduledExecutorService:对象类型
service.schedule() :用于执行一次任务,传三个参数(定时执行的任务;时长数字;时长数字的时间单位,TimeUnit的常量指定)
service.scheduleAtFixedRate(new Runnable() :根据某个周期固定一直执行,传多个参数【任务;延迟时长数字(第一次执行在什么时间以后);周期时长数字(每间隔多久执行一次);时长数字的单位】

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值