Java并发编程实战 -- 笔记1

类的标注

我们使用了3个类级别的标注(用来说明了类和类成员的并发属性)来描述类的线程安全性保证:@Immutable,@ThreadSafe和@NotThreadSafe。

@Immutable表示类是不可变的,它包含了@ThreadSafe的含义。

@NotThreadSafe是可选的,如果一个类没有标注为线程安全的,那么就应该加上它不是线程安全的,但如果想明确地表示这个类不是线程安全的,那么就可以使用@NotTreadSafe

由于多个线程要共享相同的内存地址空间,并且并发运行,因此它们可能会访问或修改其他线程正在使用的变量。

当然,这也是一种极大的便利,因为这种方式比其他线程间通信机制更容易实现数据共享(利用Java堆的对象共享???)。

当多个线程同时访问和修改相同的变量时,将会在串行编程模型中引入非串行因素,而这种非串行性是很难分析的。

要使多线程程序的行为可以预测,必须对共享变量的访问操作进行协同,这样才不会在线程之间发生彼此干扰。

幸运的是,Java提供了各种同步机制来协同这种访问

结合虚拟机理解上面这段话,因为虚拟机中的内存区域划分是:线程拥有自己的虚拟机栈和程序计数器,而Java对象所在的堆和包含类信息的方法区都是线程共享的,所以会存在多个线程中的方法同时操作Java堆中同一个对象的成员变量,即导致某个线程会修改其他线程正在使用的变量。

线程无处不在

当JVM启动时,它将为JVM的内部任务(例如,垃圾收集、终结操作等)创建后台线程,并创建一个主线程来运行main方法。(线程有主次之分么???)

当Java程序启动时,一个线程立刻运行,该线程通常叫做程序的主线程(main thread),因为它是程序开始时就执行的。主线程的重要性体现在两方面:

  • 它是产生其他子线程的线程
  • 通常它必须最后完成执行,因为它执行各种关闭动作

Timer。Timer类的作用是使任务在稍后的时刻运行,或运行一次,或周期性运行。

Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。

引入Timer可能会使串行程序变得复杂,因为TimerTask将在Timer管理的线程中执行,而不是由应用程序来管理。如果某个TimerTask访问了应用程序中其他线程访问的数据,那么不仅TimerTask需要以线程安全的方式来访问数据,其他类也必须采用线程安全的方式来访问该数据。

通常,要实现这个目标,最简单的方式是确保TimerTask访问的对象本身是线程安全的,从而就能把线程安全性封装在共享对象内部

 

线程安全性

怎么理解一个对象是不是线程安全的?

一个对象是否需要是线程安全的,取决于它是否被多个线程访问。这指的是在程序中访问对象的方式,而不是对象要实现的功能

要使得对象是线程安全的,需要采用同步机制来协同对对象可变状态的访问,如果无法实现协同,那么可能会导致数据破坏以及其他不该出现的结果。

要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的(Shared)和可变的(Mutable)状态的访问。

  • 对象的状态是指存储在状态变量(例如实例或静态域)中的数据;
  • “共享”意味着变量可以由多个线程同时访问;
  • “可变”意味着变量的指在其生命周期内可以发生变化;

当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。

在线程安全类中封装了必要的同步机制,因此客户端无须进一步采取同步措施。

竞态条件:由于不恰当的执行时序而出现不正确结果的情况。

猜你喜欢

转载自blog.csdn.net/WalleIT/article/details/87778232