多线程基本语法①

一、创建线程的方式

1.使用Thread重写run

2.实现Runnable接口,重写run

搭配Thread类才能真正在系统中创建线程。

3.继承Thread,重写run,使用匿名内部类

4.实现Runnable,重写run,匿名内部类

5.lambda表达式(匿名函数/方法)

        lambda表达式这个写法相当于实现了Runnable重写run,lambda代替了Runnable的位置。编译器编译时,Thread有好多版本,依次匹配,Runnable能匹配上,有run方法,无参数,正好和lambda匹配。

二、Thread其他常见的属性和方法

1.Thread的常见方法:

1.Thread():创建线程对象
2.Thread(Runnable target):使用Runnable对象创建线程对象
3.Thread(String name):创建线程对象,并命名
4.Thread(Runnable target,String name)使用Runnable对象创建线程并命名
5.Thread(ThreadGroup group,Runnable target)线程可以被分管理=>线程组

        该线程组为java中的概念,与系统内核中的线程组不是一个东西。

2.Thread的常见属性:

1.ID        getId():

JVM自动分配的身份标识,保证唯一性

2.名称       getName()
3.状态       getState():

进程中有就绪状态和堵塞状态。Java对线程状态进一步区分(比系统原生状态更丰富)

4.优先级        getPriority():

线程的优先级,在Java中,设置优先级效果不明显<=>系统随机调度

5.是否有后台线程     isDaemon():  

daemon守护,守护线程。例如:有两个线程,main已经结束了,t还在执行,但进程仍在继续执行,直到Process finished...才是进程结束。

        创建线程,默认为前台线程=>阻止进程结束=>只要前台线程没执行完,进程就不结束(即使main已执行完毕)

t.setDaemon(true)在strat之前,设置线程为后台线程(不能在strat后设置)

6.是否存活       isAlive():

内核中的线程(PCB)是否还存在。

        Java代码中定义的线程对象(Thread)实例,虽然表示一个线程,但这个对象本身的生命周期和内核中的PCB生命周期是不完全一样的。

Thread t = new Thread();=>t对象有了,但内核PCB还没有,isAlive为false

t.start();=>真正在内核中创建出该PCB,isAlive为true

当线程run执行完了,内核中的线程就结束了(内核PCB释放)isAlive为false,但t变量可能还在

7.是否被中断/终止        isInterrupted()

使用Thread实例内部自带的标志位,代替刚才手动创建的isQuit变量。

三、启动线程:start()

调用strat创建出新线程,本质=>start调用系统api来完成创建线程的操作

run和start的区别

t.start():创建一个新的线程,由新的线程执行操作

t.run():还是在主线程中执行操作

四、终止线程:interrupt()

代码一:使用isQuit

isQuit不能作为main方法中的局部变量。lambda表达式中:变量捕获

lambda表达式/匿名内部类可以访问到外面定义的局部变量。但是捕获的变量的是final/事实final

(匿名内部类访问外部的成员,不受到变量捕获的影响)

由于此处isQuit确实要修改,不能写成final,也不是事实final。

Java对于变量捕获有final的限制

isQuit是局部变量时,是属于main方法的栈帧中的,但是Thread lambda有自己独立的栈帧(不同线程)=>生命周期不同

导致:main方法执行完了,栈帧销毁了,但Thread栈帧还在,想继续使用isQuit。

解决方法:变量捕获本质上就是传参。=>让lambda表达式在自己的栈帧中创建一个新的isQuit并把外面的isQuit拷贝过来(为了避免里外isQuit的值不同步,java就不让修改isQuit)

代码二:让Thread对象内置变量

使用Thread实例内部自带的标志位代替刚才手动创建的isQuit变量。

在执行sleep的过程中,调用interrupt,有可能sleep休眠时间还不到被提前唤醒。

提前唤醒:1.抛出InterruptedException,被catch获取到

                    2.清除Thread对象的isInterrupted标志位

=>通过interrupt方法,将标志位设为true,但sleep提前唤醒又设为false,若想让线程结束,在catch中加上break

在Java代码中,会以异常的形式体现问题。可通过catch代码,对这些异常进行处理。

①尝试自动恢复,如出现一个网络通信相关的异常,在catch尝试重连网络。

②记录日志,(将异常信息记录到文件中)不立即解决

③发出警报,针对一些比较严重的问题

④有少数的正常业务逻辑,会依赖到catch,如文件操作中有些方法,就是要用catch来结束循环。

在Java中,线程的终止是一种“软性”操作,必须要对应的线程配合才能终止。

        系统原生的api还提供了强制终止线程的操作 =>无论线程是否配合,无论线程执行到哪个代码,都能强行终止线程。 但在Java的api中没有提供。(弊大于利

如果强行中断一个线程,很可能线程执行到一半,会出现一些残留的临时性质的“错误”数据。

五、等待线程(结束):join()

多个线程的执行顺序是不确定的(随机调度,抢占式执行

线程底层的调度是无序的,但可以通过一些api来影响到线程执行顺序。

join方式:影响线程结束的先后顺序(使线程堵塞)

join<=>线程最核心的api之一,任何一个线程都可调用。

代码一:

t.join():让main线程等待线程结束;执行join时,看t线程是否在执行,若t在执行,main线程就会堵塞(不会参与cpu执行);t线程运行结束,main线程就会从堵塞中恢复,继续执行。

1.死等

2.带有超时时间的等,带有一个时间上限。

代码二:

让主线程创建一个新线程,由新线程完成运算,主线程获取结果

把整个运算分成两段,分别运算。(提升速度)

但线程数不能无线提升,一定程度后无法提升速度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值