关于 Java Concurrency
自从Java诞生之时,Java 就支持并行的概念,比如线程和锁机制。这个教程帮助开发多线程Java程序员能够理解核心的Java并行理念以及如何使用他们。 内容涉及到Java语言中的线程, 重练级以及轻量级同步机制 以及JavaSE 5 中的锁,原子量 并行容器,线程调度 以及线程执行者。 开发人员使用这些知识能够开发好并发线程安全的Java 应用程序。
Java 并行的概念(Java Concurrency Concepts)
概念
|
描述
|
Java 内存模型
|
在JavaSE5 JSR133规范中详细定义了Java内存模型 Java Memory Model(JMM),该模型定义了相关的操作 比如读,写操作,以及在监视器上的同步。 这些操作按 Happens-before的顺序。
这个定义保证了一个线程可以看到另一个线程操作的结果,同时保证了同步的程序, 以及如何定义一个不变的属性 等等。
|
监视器
|
在Java中,任何一个对象都有一个监视器,来排斥共享访问临界区域的代码。这些临界区可以是一个方法 或者是一段代码块,这些临界区域作为同步块。线程只有获取该监视器才能执行同步块的代码。当一个线程到达这块代码是,首先等待来确定是否其他线程已经释放这个监控器。监控器除了排斥共享访问,还能通过Wait 和Notify来协调线程之间的交互。
|
原子属性
|
除了Double 和long类型,其他的简单类型都是原子类型。Double和long 类型的修改在JVM分为两个不封。为了保证更新共享的Double和Long类型,你应该将Double和long 的属性作为Volatile 或者将修改代码放入同步块中。
|
竞争情况
|
当许多线程在一系列的访问共享资源操作中,并且结果跟操作顺便有关系的时候,就发生了竞争情况。
|
数据竞争
|
数据竞争涉及到当许多线程访问不是non-final或者non-volatile 并没有合适的同步机制的属性时,JMM不能保证不同步的访问共享的熟悉。数据竞争导致比个预知的行为。
|
自公布
|
还没有通过构造方法实例化对象之前,把这个对象的引用公布时不安全的。
一种是通过注册一个监听器,当初始化的时候回调来发布引用。
另一种是在构造方法里面启动线程。这两种都会导致其他线程引用部分初始化的对象。
|
Final属性
|
Final属性必须显示的赋值,否则就会有编译错误。一旦赋值,不能被修改。将一个对象引用标记为Final只能保证该引用不会被修改,但该对象可以被修改。比如一个Final ArrayIist不能改变为另一个ArrayList 但你可以添加或者修改这个List的对象。在构造方法之后,一个对象的Final 属性是冻结的,保证了对象被安全的发布。其他线程可以在构造方法时看到该变量,甚至在缺乏同步的机制下。
|
不变对象
|
Final 属性从语义上能够保证创建不变对象。而不变对象可以再没有同步机制下多线程共享和读取。为保证该对象是不变的,必须保证如下:
这个对象被安全的发布,this引用不能在构造方法的时候被发布
所有的属性都是Final的
应用的对象必须保证在构造方法之后不能被修改。
这个对象需要声明为Final 保证子类违法这些原则。
|
Protecting shared data
保护共享的数据
线程安全的程序需要开发人员在需要修改共享的数据时使用合适的锁机制。锁机制建立的
适合JMM的顺序,保证对于其他程序的可视性。
当在同步机制外修改共享的data时,JMM不能保证其一致性。 JVM提供了一些方法来保证其可视性。
Synchronized
每一个对象实体都有一个监视器(来之于Object对象),这个监视器能被再某一线程中锁定。Synchronized关键字来指定在方法或者代码块上持有该对象监视器上的锁定。当某一线程同步修改一属性,后续线程将能看到被该线程修改的数据。
Lock
java.util.concurrent.locks 包提供了Lock的接口,ReentrantLock实现了类似Synchronized关键字的功能。同时还提供了额外的功能,比如不是阻塞的tryLock()方法和释放锁。
public class Counter {
private final Lock lock = new ReentrantLock();
private int value = 0;
public int increment() {
lock.lock();
try {
return ++value;
} finally {
lock.unlock();
}
}
}
同时,在多线程高冲突的情况下,ReentrantLock要比Synchronized效率好。
ReadWriteLock
java.util.concurrent.locks 包提供了一个读写锁的接口,这个接口定义了读和写的一对锁,
一般允许并行的读和排他的写。下面的代码展示了上述功能。
public class Statistic {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private int value;
public void increment() {
lock.writeLock().lock();
try {
value++;
} finally {
lock.writeLock().unlock();
}
}
public int current() {
lock.readLock().lock();
try {
return value;
} finally {
lock.readLock().unlock();
}
}
}
Volatile
Volatile 关键字使其属性对于后续的线程的可见性。
public class Processor implements Runnable {
private volatile boolean stop;
public void stopProcessing() {
stop = true;
}
public void run() {
while(! stop) {
// .. do processing
}
}
}
注意:将array标记为Volatile不能保证数组里面元素的Volatile,只能保证数组的引用时
可见的。使用AtomicIntegerArray 来保证整个数组都是可见的。
原子类
Volatile 的缺点是只能保证可见性。不能保证修改结果的可见性。而java.util.concurrent.atomic
包包含了一组支持原子操作的类来弥补Volatile的不足。
public class Counter {
private AtomicInteger value = new AtomicInteger();
public int next() {
return value.incrementAndGet();
}
}
ThreadLocal
ThreadLocal存贮了该线程所需要的数据,不需要锁的机制。一般而言,ThreadLocal 存放当前的事务和其他资源等。如下代码,TransactionManager中,ThreadLocal 类型的currentTransaction 存贮了当前事务。
public class TransactionManager {
private static final ThreadLocal<Transaction> currentTransaction =
new ThreadLocal<Transaction>() {
@Override
protected Transaction initialValue() {
return new NullTransaction();
}
};
public Transaction currentTransaction() {
Transaction current = currentTransaction.get();
if(current.isNull()) {
current = new TransactionImpl();
currentTransaction.put(current);
}
return current;
}
}
并行容器
合理维护共享数据一致性的核心技术是在访问数据时采取同步机制。这种技术使得所有访问共享数据的方式保证了同步的原则。java.util.concurrent提供了可以并行使用的数据结构。通常而言,使用这些数据结构优于通过Synchronized包装的非同步集合。
同步的 lists and sets
类
|
描述
|
CopyOnWriteArraySet
|
CopyOnWriteArraySet
提供Copy-On-Write的语义 即:每当修改某一数据时在整个容器内容拷贝上修改,然后将该备份同步入容器。
|
CopyOnWriteArrayList
|
类似CopyOnWriteArraySet
|
ConcurrentSkipListSet
|
JSE6提供的并行访问可以排序的Set。
|
并行 maps
java.util.concurrent扩展map接口,提供了名叫ConcurrentMap的并行Map。
如下面所有的操作都是原子性的。
方法
|
描述
|
putIfAbsent(K key, V value) : V
|
如果Key没有在该Map中,将Key Value存入。
否则不做任何处理。
如果没有该Key 返回Null
如果有 返回以前的值。
|
remove(Object key, Object value)
: boolean
|
如果Map中包含该key则移出该Value 否则不做任何操作。
|
replace(K key, V value) : V
|
如果Map中有该Key 则用该Value值替换久值。
|
replace(K key, V oldValue, V
newValue) : boolean
|
如果Map中有该Key且值为oldValue时,用newValue替换该久值。
|
下面是具体实现类:
类
|
描述
|
ConcurrentHashMap
|
内部的segment实现了并行的读取。
|
ConcurrentSkipListMap
|
JSE6提供的并行访问可排序的Map。
|
Queues
作为生产者于消费者管道的Queues,生产的条目从一头放入,然后从另一头取出,典型的先进先出的顺序。Queues接口在JSE5加入java.util包里,应用于单线程的环境。最主要用于多生产者消费者的情况下。所有的读写操作都在同一Queue上。在Java.util.concurrent包的blockingQueues接口扩张了Queue并处理了Queue可能已经被生产者添加慢的情况,或者消费者已经读取或者取出完,Queue为空的情况。在这些情况下,BlockingQueue提供了阻塞的机制。可以设定阻塞的时间或者阻塞的条件。
下表反应了Queue于BlockingQueue对处理特殊条件下的不同策略。
类
|
策略
|
插入
|
移除
|
检查
|
Queue
|
扔出异常
|
Add
|
remove
|
element
|
返回特定的值
|
Offer
|
poll
|
peek
|
Blocking Queue
|
永远的阻塞
|
Put
|
take
|
n/a
|
在设定的时间阻塞
|
Offer
|
poll
|
n/a
|
下面是具体的实现类。
PriorityQueue
|
唯一非并行的Queue。用于单线程 处理排序的集合。
|
ConcurrintlinkedQueue
|
没有容量限制的的并行实现,不支持阻塞。
|
ArrayBlockingQueue
|
基于数组 有容量限制的 阻塞Queue。
|
LinkedBlockingQueue
|
最通用的实现阻塞容量限制的Queue。
|
PriorityBlockingQueue
|
相对于先进先出,该Queue的顺序基于Comparator的优先级别,没有容量限制。
|
DelayQueue
|
没有容量限制的Queue,有一个延迟值。
只有延迟时间超过时才能被移除。
|
分享到:
Global site tag (gtag.js) - Google Analytics
|
相关推荐
### Java多线程学习资料知识点解析 #### 一、引言 Java作为一种广泛使用的编程语言,在并发编程领域具有独特的优势。多线程是Java中实现并发处理的核心技术之一,能够显著提升程序的性能和响应性。本文将深入探讨...
Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java...
Java多线程学习是编程领域中的重要一环,特别是在服务器端和网络编程中,多线程技术能够有效地利用系统资源,提高程序的并发性。FTP(File Transfer Protocol)上传则是通过网络将本地文件传输到远程服务器的过程。...
总的来说,Java多线程学习涵盖了线程的创建、同步、通信、调度以及异常处理等多个方面,深入理解和掌握这些知识点对于提升Java程序的性能和复杂性至关重要。通过阅读提供的"Java多线程.pdf"文档,你可以进一步了解和...
Java多线程是一块重要的内容,李兴华讲解的Java是一个很好的资源
这篇学习笔记将深入探讨Java多线程的核心概念、实现方式以及相关工具的使用。 一、多线程基础 1. 线程与进程:在操作系统中,进程是资源分配的基本单位,而线程是程序执行的基本单位。每个进程至少有一个主线程,...
下面是对Java多线程学习的详细解析。 1. **多线程概述**: 多线程是指一个程序内可以同时执行多个独立的执行流,每个执行流被称为一个线程。Java通过Thread类来代表线程,每个线程都有自己的生命周期,包括新建、...
总的来说,Java多线程学习涵盖了线程的创建与管理、并发工具的使用、以及高级并发编程策略。理解并掌握这些知识,能够帮助开发者编写出高效、可靠的多线程应用。而Doug Lea的工作不仅推动了Java并发技术的发展,也为...
在“Java多线程学习总结6”这个主题中,我们可以深入探讨Java多线程的实现、管理及优化。下面将详细阐述相关知识点。 1. **线程的创建方式** - **继承Thread类**:自定义类继承Thread类,并重写run()方法,创建...
### CoreJava多线程学习总结 #### 一、基本概念 多线程是现代软件开发中非常重要的一个概念,尤其在Java这样的高级编程语言中,它使得程序能够更高效地利用计算机资源,实现并发处理任务。为了更好地理解CoreJava...
### Java多线程学习教程知识点详解 #### 一、Java多线程简介 Java多线程编程是指在Java应用程序中利用多线程技术提高程序的并发性和效率。相比于C或C++等语言,Java提供了更加高级的语言级支持,使得开发者能够...
【Java 多线程学习详细总结】 在Java编程中,多线程是处理并发执行任务的关键技术。本文将深入探讨Java中的多线程概念、实现方式、线程状态转换、线程调度、线程同步以及数据传递等相关知识。 1. **扩展`java.lang...
本资料“Java多线程学习-动力节点共22页.pdf.zip”提供了对Java多线程的深入学习,旨在帮助开发者掌握这一关键技术。 1. **线程基础**:Java中的线程是通过`Thread`类或者实现`Runnable`接口来创建的。通过继承`...
Java多线程是Java编程中的一个核心概念,它允许程序同时执行多个...PPT文件"Ch17 多线程.ppt"可能会包含更详细的讲解,包括线程安全的数据结构、并发集合、线程间的通信机制等内容,这些都是Java多线程学习的重要部分。
### Java多线程学习笔记 #### 一、线程的基本概念 在计算机科学中,**线程**(Thread)是程序执行流的最小单位。一个标准的程序只能做一件事情,而通过多线程技术,可以让程序同时处理多个任务。在Java中,线程是...
Java多线程学习基础原理主要涉及以下几个方面: 1. 线程的创建和启动 Java提供了两种创建线程的方式:继承Thread类和实现Runnable接口。当创建一个Thread类的子类对象并调用start()方法时,会启动一个新的线程,并...