前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文读懂《Java并发编程实战》:第1章 多线程安全性与风险

一文读懂《Java并发编程实战》:第1章 多线程安全性与风险

作者头像
后台技术汇
发布2022-05-28 12:48:59
2120
发布2022-05-28 12:48:59
举报
文章被收录于专栏:后台技术汇

多线程是在同一个程序内部并行执行,因此会对相同的内存空间进行并发读写操作。

  • 如果一个线程在读一个内存时,另一个线程正向该内存进行写操作,那进行读操作的那个线程将获得什么结果呢?是写操作之前旧的值?还是写操作成功之后的新值?或是一半新一半旧的值?
  • 如果是两个线程同时写同一个内存,在操作完成后将会是什么结果呢?是第一个线程写入的值?还是第二个线程写入的值?还是两个线程写入的一个混合值?

因此对于多线程代码,如果没有合适的预防措施,任何结果都是可能的。

Java 是最先支持多线程的开发的语言之一,Java 从一开始就支持了多线程能力,因此 Java 开发者能常遇到上面描述的问题场景。

多线程的优势

操作系统为各个独立执行的进程分配各种资源,包括内存,文件句柄以及安全证书。如有需要线程之间甚至可以进行一些粗粒度的通信机制来交换数据,例如:套接字、信号处理器、共享内存、信号量以及文件等。

多线程出现的原因主要有3个:

资源利用率。某些情况下程序会等待某些外部操作,等待期间完全可以用于其他线程的执行,提高资源利用率。

公平性。不同用户与程序对计算机的资源有同等使用权,高效运行方式是提高粗粒度的时间分片(Time Slicing)让这些用户与程序共享计算机资源。

便利性。将复杂度任务拆解为多个子任务程序,每个程序在必要时互相通信,这样的实现会更加简化工作。

多线程的优势主要有4个:

充分发挥多处理器的计算能力。线程是最基本的调度单位,多线程有助于提高提高资源利用率,进而提升系统的吞吐率。

利于建模的简单性。化繁为简,我们现有的框架可以实现这个目标,例如:Servlet 和 RMI (Remote Method Invocation),框架解决细节问题,例如请求管理、线程创建、负债平衡,并在正确时刻分发给正确应用程序组件。

简化异步事件处理。我们现在的操作系统提供了一些高效的分发来实现多路IO,例如Unix 的select 和 poll等,Java 类库获得一族非阻塞的I/O包,这使得系统支持的线程数量得到极大提升。

更灵敏的响应界面。主要是GUI应用程序,例如:AWT 和 Swing 等,采用事件分发线程(Event Dispatch Thread,EDT)替代主事件循环。

多线程的风险

Java 对多线程的支持是一把双刃剑,既简化了并发应用程序的开发,也提高对开发人员的技术要求。

多线程的风险主要体现在3个方面:

安全性问题:“永远不发生糟糕的事情”。多线程下会发生一种常见的并发安全问题,称为竞态条件(Race Condition),这时线程会由于无法预测的数据变化而出错,例如:多线程访问修改相同的变量会引入 非串行因素,这种问题极难定位。

  • 这个例子是非线程安全的使用:
代码语言:javascript
复制
@NotThreadSafe
public class UnsafeSequence {
private int value;
/** 返回唯一值**/
public int getNext(){
return value++;
  }
}
  • 原因是线程的执行非确定性:
  • 这个例子是线程安全的使用:
代码语言:javascript
复制
@ThreadSafe
public class SafeSequence {
private int value;
/** 返回唯一值**/
public synchronized int getNext(){
return value++;
  }
}

活跃性问题:“某件正确的事情最终会发生”。串行程序的活跃性问题之一是无意中造成的死循环;多线程程序的活跃性问题是:死锁、饥饿、活锁等。

性能问题:“我们通常希望正确的事情尽快发生”。性能问题包括多方面:服务时间过长,响应不灵敏,吞吐率过低,资源消耗过高或者可升缩性较低等。

JVM与Java框架对多线程的支持

几乎所有Java应用程序都是多线程的,当 JVM 启动时,它将为 JVM 的 内部任务(如:垃圾收集、终结操作等)创建后台线程,并创建一个主线程运行 main 方法

常见的Java 多线程模块有4个:

Timer:定时器。

Servlet 和 JSP(JavaServer Page):Servlet 框架用于部署网页程序 和 分发来自HTTP 客户端请求。抵达服务器的请求会通过一个过滤器,然后分发到正确的 Servlet 或 JSP。每个 Servlet 是一个程序逻辑组件,高吞吐率的网站,多个客户端可能同时请求一个Servlet的服务。

因此, Servlet 需要满足被多线程访问的要求,它必须是线程安全的。

RMI(Remote Method Invocation):RMI 能够调用其他 JVM 的运行对象,通过 RMI 调用远程方法时,传递的参数会被打包(列集)到一个字节流,通过网络传输给远程 JVM,然后由远程 JVM 拆包(散集)并传递给远程方法。

当 RMI 代码调用远程对象,这个调用会被哪个线程执行?这其实是在由 RMI 管理的线程中进行调用的,因此,它必须是线程安全的。

Swing 和 AWT:GUI 应用程序的异步性。

总结

本节主要关注Java 多线程,讲述了多线程的基础知识:什么是多线程,多程带来了哪些问题,多线程有哪些优点,以及JVM与Java框架对多线程的支持。对于线程模型,可以点击《一文带你读懂:系统线程模型与实现原理》进行了解。

—END—

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后台技术汇 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 多线程的优势
  • 多线程的风险
  • JVM与Java框架对多线程的支持
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档