并发编程 进程与线程相关

本文详细解析了进程、线程与协程的概念及其区别,深入探讨了Java中线程的实现方式,包括Thread类、Runnable接口及Callable的使用。同时,文章还介绍了线程的生命周期、线程间通信机制、线程中断处理以及锁的高级应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

进程 线程 协程

进程是资源分配的最小单位
线程是CPU调度的最小单位,同一进程的所有线程共享该进程的所有资源
同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段(Java虚拟机栈),用来存放所有局部变量和临时变量、程序计数器(字节码行号指示器)

线程没有独立的地址空间,如果线程挂了 所属进程也挂了。所以多进程的程序要比多线程的更加健壮
进程切换比线程切换开销大

协程(微线程):协程和线程一样共享堆,不共享栈,协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈(在一个线程内执行)则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。

Thread start() run()区别

在这里插入图片描述

多线程

多线程的实现

(1)继承Thread类
(2)实现Runnable接口
(3)使用ExecutorService、Callable、Future实现有返回结果的多线程

Thread 与 Runnable 的区别

(1)联系:
1、Thread类实现了Runable接口。
2、都需要重写里面Run方法。
(2)不同:
1、实现Runnable的类更具有健壮性,避免了单继承的局限。
2、Runnable更容易实现资源共享,能多个线程同时处理一个资源。

获取线程的返回值的方法 细说Callable

在这里插入图片描述1.通过FutureTask
Callable泛型接口实现需要重写call()方法 并且需要抛出异常 这个方法是返回一个泛型值
实现完成后 可以用FutureTask 它的构造函数可以传入一个实现Runnable接口的类的实例
FutureTask继承RunnableTask RunnableTask继承Future接口 所以有
isDone() get()方法
并且因为继承了Runnable 启动需要 new Thread(futuretask).start();

2.通过线程池
ExecutorService es = Executor.newcashedThreadPool();//创建线程池
Future future = es.submit(new myCallable())然后又可以用isDone() 和get()方法
最后记得关闭线程池 es.shutdown();

execute()与submit()

execute用来提交不需要返回值的方法 无法判断是否成功被线程池执行
submit()会返回一个future对象 而future对象可以调用get()获取返回值 get会阻塞当前线程直到任务完成 而get(long timeout)会阻塞一段时间立即返回

线程的六个状态

在这里插入图片描述

sleep与wait 的区别

在这里插入图片描述Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。但是sleep是不释放锁的。

wait 与 notify

锁池:EntryList

在这里插入图片描述等待池:WaitSet
在这里插入图片描述
在调用 wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用 wait()方法。调用后进入到等待池不会竞争该对象的锁

notifyAll()方法会让所有等待池的线程进入到锁池去竞争锁
notify()是随机让等待池中的一个线程进入到锁池去竞争锁

yield join

在这里插入图片描述
yield让一个线程会从运行台到就绪态
在这里插入图片描述join()一般在主线程中使用,一个线程调用join()方法后 主线程要等待该线程执行完毕后才去执行

如何安全的中断一个线程

一.stop和suspend为什么不安全
stop():
1.即刻停止run()方法中剩余的全部工作,包括在catch或finally语句中,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。

2.会立即释放该线程所持有的所有的锁,导致数据得不到同步的处理,出现数据不一致的问题。
suspend():
因为suspend方法并不会释放锁,如果使用suspend的目标线程对一个重要的系统资源持有锁,那么没任何线程可以使用这个资源直到要suspend的目标线程被resumed,如果一个线程在resume目标线程之前尝试持有这个重要的系统资源锁再去resume目标线程,这两条线程就相互死锁了

二.正确的方法
应该在自己的Thread类中置入一个标志例如用while(isInterrrupted())或者自己设置标志位,用于控制目标线程是活动还是停止。如果该标志指示它要停止运行,可使其结束run()方法。如果目标线程等待很长时间,则应使用interrupt()方法来中断该等待。

在这里插入图片描述

互斥锁的特性

  • 可见性
    可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看到修改的值。
    在多核时代,每颗CPU都有自己的缓存,这时CPU缓存与内存的数据的一致性就没那么容易解决了。当多个线程在不同的CPU上执行时,此时操作的时不同CPU上的缓存。
    在这里插入图片描述

  • 原子性

  • 我们把一个或者多个操作在CPU执行的过程中不被中断的特性成为原子性

synchronized

synchronized锁的是对象 包括类锁也是锁的对象 如果类锁中线程传入new class 那么也是同一个对象锁 而 类锁与对象锁是不干扰的

获取对象锁与类锁的方法

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值