Java并发性和多线程

本文介绍了Java多线程相关知识。阐述了并发性和多线程的区别联系,介绍了并发模型和Java多线程的创建方式。分析了竞态条件、临界区、线程安全与共享资源的关系,讲解了Java同步块的使用。还涉及线程通信方法,以及同步块可能导致的死锁问题和避免策略。

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

转载自http://ifeve.com/java-concurrency-thread-directory/

简要总结

并发性和多线程的区别和联系

多线程是并发的一种实现。并发还可以使用分布式/多进程实现。

并发模型:并行工作者、流水线工作者/事件驱动模型

Java多线程两/四种创建方式

继承Thread,(匿名/不匿名)子类

实现Runnable接口,(匿名/不匿名)类

竞态条件(race condition)和临界区()

当多个线程同时访问某一代码区,对共享的资源做出了更改,若运行结果与多个线程的访问顺序有关,则称形成了竞态条件,与之相关的这一代码区域称为临界区。

多个线程同时更新共享资源时会形成竞态条件。

线程安全与共享资源

多线程中某些资源是被共享的。多个线程同时更新共享资源时会形成竞态条件。允许被多个线程同时执行的代码称作线程安全的代码。线程安全的代码不包含竞态条件。要明白哪些资源是线程安全的(方便使用的)。

  • 局部基本变量(线程安全)
  • 局部对象引用(方法中对象的引用没有逃逸,或者没有被其他线程引用,就是安全的)
  • 对象成员(不安全)
  • 使用不可变对象(没有setter的类实例,线程安全)
  • ThreadLocal(创建的变量只被同一个线程读写,在多个线程中有不同的副本,仅初始值相同。线程安全)

参考java内存模型可以明白它们为什么是线程安全或不安全的。

线程控制逃逸规则:如果一个资源的打开、使用、销毁都是在一个线程中完成的。且不会脱离该线程的控制,该资源的使用就是线程安全的。

资源:包括对象、数组、文件、数据库连接、套接字等。

即使对象本身是线程安全的,但对象使用的资源可能不安全,如包含了数据库多步操作。

Java同步块

多线程开发时,要使用线程安全的资源(不存在竞争)。对于线程不安全的资源/存在竞争的的情况,使用同步块来避免竞争。

同步块可以保证一次只有一个线程进入临界区(加同步块的代码区),其他线程被阻塞(不恰当的编程可能导致一直阻塞,也就是死锁)。Java中的同步块使用synchronized关键字来标记。同步都加在类对象上。

实例方法同步

静态方法同步

实例方法中的同步块

静态方法中的同步块

线程通信

在保证线程安全的基础上,线程间应当可以通信

使用共享对象通信:共享对象中加锁(加同步块)防止竞争,在不同线程中使用此对象。

简单实现:共享对象中加锁(加同步块)防止竞争,线程1发送消息,线程2通过轮询等待(忙等待,缺点是cpu资源消耗大)

Java内建通信机制:共享对象加锁(使用同步块),在同步块中使用wait()\notify()\notifyAll()函数。

解决信号丢失(notify在wait之前):Java内建通信机制+判断共享对象成员变量(保存notify状态)

解决假唤醒(特殊情况下wait返回向后执行):Java内建通信机制+循环判断共享对象成员变量(保存notify状态)

注意不要使用字符串常量作为共享对象(JVM中相同的字符串常量指向了同一个地址),还有全局对象。

死锁

同步块解决线程不安全代码的竞争问题,但同步块可能有死锁的隐患。当一个线程进入同步块(代码临界区),其他线程被阻塞(不恰当的编程可能导致一直阻塞,也就是死锁)。

例子:如果线程1锁住了A,然后尝试对B进行加锁,同时线程2已经锁住了B,接着尝试对A进行加锁,这时死锁就发生了。线程1永远得不到B,线程2也永远得不到A,并且它们永远也不会知道发生了这样的事情。为了得到彼此的对象(A和B),它们将永远阻塞下去。

2+线程的死锁

数据库更新记录的死锁

死锁避免

加锁顺序

加锁时限

死锁检测


mark vert.x

未学习:java中的锁,信号量,线程池等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值