Java-多线程并发01并发基础知识

线程的声明周期及其状态:

 

 

 

 

 

实现线程的三种方式:

1.继承Thread重写Run方法。

 

start方法调用后,线程处于就绪态,执行run方法,执行完毕后处于终止态。

优点:获取线程直接在Run里边this。  不需要Thread.currentThread()。

缺点:不支持多继承,任务和代码没有分离,多个线程执行相同任务需要多份代码。如果运行第二遍start会报错ill'egalThreadStateException

 2.Runable接口实现

优点:多个线程共用一个task代码逻辑。如果由需要可以加参数区分。同时实现了Runable接口的还可以继承其他的类。

缺点: 和Runnable一样,没有return返回值。

3.FutureTask:

首先创建一个静态类继承Callable接口,并覆盖他的cal方法。

在main函数中,首先创建一个FutureTask对象,并在他的构造器中把实现Callable接口的对象传进去。

然后创建一个FutureTask对象作为线程并启动他,最后可以通过get方法等待任务执行完毕并获取返回值。(这里get方法需要抛一个运行异常因为需要等待他的结果)

 

Waits if necessary for the computation to complete, and then retrieves its result.

 

 

 

 必要时等待计算完成,然后检索其结果。

 

 

 

 

三种方式的优缺点:

Thread:方便传参数,可以在子类里面添加变量,通过set方法设置参数或者通过构造器进行传递。 由于这个是继承,所以不能再去继承其他的类。

Runable:只能使用主线程的final变量。

Future:可以拿到返回结果

 

wait(): 调用的线程被阻塞挂起。需要实现获得监视器锁

唤醒的条件:

1).其他线程调用了该共享对象的notify()、notifyAll()

2).其他线程调用了该线程的interrupt(),该线程抛出InterruptException异常返回。

如果调用wait()方法的线程没有实现获取该对象的监视器锁,则会抛出illegalMointorStateException异常。

 

如何获取共享变量的监视器锁?

执行Synchronized同步代码块时,使用该共享变量作为参数。

调用该共享变量的方法,并且该方法使用Synchronized修饰。

 

 

 

 

 

 

 简单来说,就是执行Synchronized代码块时把共享变量作为参数,然后再去执行共享变量的方法,就会获得共享变量的监视器锁。

对于锁和监视器的理解:https://www.cnblogs.com/keeplearnning/p/7020287.html

锁:

监视器:java中的每个对象都有一个内部锁和内部条件。如果一个方法用synchronized关键字声明,那么,它表现的就像一个监视器方法。通过wait/notifyAll/nofify来访问条件变量

 

虚假唤醒:

一个线程有可能会不通过正常的方法(notify,中断,等待超时)被从挂起状态变成可运行状态。

所以需要利用条件循环去不断的让他处于挂起状态。

while(条件不满足){

obj.wait();

}

 

特性:当线程调用共享变量的wait()方法后只会释放共享变量上的锁,如果共享变量在的这个线程还有其他共享变量的锁,对其他共享变量的锁不负责。

   如果在使用wati阻塞挂起的过程中被其他线程调用interrupt中断,会抛出InterruptException异常。  

 

wait(long timeout):如果在timeout时间内没有被唤醒,会因超时返回。  timeout的值为负会报错。

wait(long timeout,int nanos):内部调用wait(long timeout),nanos>0时 timeout++

 

notify:

随机唤醒一个共享变量调用wait挂起的线程。被唤醒的线程不会立马获得共享对象的监视器锁,仍需要和其他的线程一起竞争该锁。

只有当前的线程获得了监视器锁,才可以调用共享变量的notify方法。

 

notifyAll:
唤醒所有被wait挂起的线程。

例子:

线程A{

synchronized(A)

A.wait

}

线程B{

synchronized(A)

A.wait

}

线程C{

synchronized(A)

A.notify

}

调用顺序。  A,B 然后等1s  允许C的notify

结果:

线程A拿到共享变量A资源的锁,挂起并释放A资源的锁

线程B拿到共享变量A资源的锁,挂起并释放A资源的锁

此时A,B都在资源A的阻塞队列

这时线程C拿到共享变量A资源的锁,进行唤醒操作,唤醒资源A的阻塞队列中的随机一个线程

线程A被唤醒,结束挂起,从wait方法返回。执行wait后面的语句。

需要注意,唤醒操作是唤醒在调用notify之前进行wait操作的线程。如果在notify之后调用的wait方法不会唤醒。

wait被唤醒后从被挂起地方继续执行下去

posted @   NobodyHero  阅读(66)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示