上面介绍了并发编程中的栅栏等JAVA并发之多线程基础(4) 。经过惟一的一个终点线来帮助肯定线程是多晚开始执行下一次操做。java
提供了一个比较底层的线程挂起操做。有点相似于
suspend()
方法,可是这个方法不建议使用。编程
park()
使得当前线程挂起。里面也是调用了Unsafe
类进行底层操做。public static void park() {
UNSAFE.park(false, 0L);
}
复制代码
2.unpark(Thread thread)
是将当前线程继续往下执行。数组
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
复制代码
LockSupport
上面的两个方法不像suspend()
与resume()
方法。在这两个方法中resume()
必须在suspend()
以前执行。不然线程就会被永远的挂起,形成死锁。而LockSupport
中的unpark
能够在park
以前。安全
package com.montos.lock;
import java.util.concurrent.locks.LockSupport;
public class LockSupportDemo {
public static Object obj = new Object();
static ChangeObjectThread t1 = new ChangeObjectThread("t1");
static ChangeObjectThread t2 = new ChangeObjectThread("t2");
public static class ChangeObjectThread extends Thread {
public ChangeObjectThread(String name) {
super(name);
}
@Override
public void run() {
synchronized (obj) {
System.out.println("in " + getName());
LockSupport.park();
}
}
}
public static void main(String[] args) throws InterruptedException {
t1.start();
Thread.sleep(100);
t2.start();
LockSupport.unpark(t1);
LockSupport.unpark(t2);
t1.join();
t2.join();
}
}
复制代码
经过上面的一个小的Demo能够看出
LockSupport
的使用方法,在使用方法中也是很简单的。以上篇幅就对JDK内的并发类进行了讲解。大多数用到了CAS无锁操做。避免线程阻塞的状况发生。多线程
在平常的业务处理中,集合类是咱们使用最多的一个操做。对应的也就是三大类:
Map
、Set
以及最后的List
。在平常并发量小的状况下,也许咱们会这么使用对应的集合操做:并发
//Map集合
private static final Map<String,String> map = Collections.synchronizedMap(new HashMap<String,String>());
//List集合
private static final List<String> list = Collections.synchronizedList(new ArrayList<String>());
//Set集合
private static final Set<String> set = Collections.synchronizedSet(new HashSet<>());
复制代码
上面的使用了Collections
中的同步方法进行包装。深刻了解里面的调用过程,也就是各个方法上面加上了synchronized
进行限制。从而达到最后线程安全的目的。若是并发量很大的话,是很会影响性能的,毕竟它使得对应的读和写操做都变成了串行。因而有了下面的几种线程安全类:ide
ConcurrentHashMap
高性能并发的Map。里面的操做是跟HashMap
是同样的。可是里面多了一种结构:Segment
(段)。static class Segment<K,V> extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
final float loadFactor;
Segment(float lf) { this.loadFactor = lf; }
}
复制代码
能够看出他是继承了重入锁进行实现的。为何会有段的概念在这里面呢?为了更好的支持高并发而设计的一个概念。每一个元素在特定的段中,将整个集合分红许多段进行管理,而高并发的时候,只要对每一个段进行控制就能起到一个同步的做用。高并发
再统计数量大小的时候,ConcurrentHashMap
中利用了CounterCell
结构体进行统计。每个段中存储了该段的大小,而后再循环求和出当前的数组大小状况。post
final long sumCount() {
CounterCell[] as = counterCells; CounterCell a;
long sum = baseCount;
if (as != null) {
for (int i = 0; i < as.length; ++i) {
if ((a = as[i]) != null)
sum += a.value;
}
}
return sum;
}
复制代码
BlockingQueue
是一个很是好的多线程共享数据的容器。当队列为空的时候,读线程就会进行等待,相反,若是当前队列已满,那么写线程就会等待。看到对应的实现类中都会有下面三个成员变量:/** Main lock guarding all access */
final ReentrantLock lock; //加锁进行控制访问
/** Condition for waiting takes */
private final Condition notEmpty;//元素获取的时候,进行判断是否为空进行阻塞
/** Condition for waiting puts */
private final Condition notFull;//元素加入的时候,判断队列是否已满
复制代码
这上面的三个变量就控制整个阻塞队列的访问以及元素的增长。从根本上来讲他并不像上面介绍的ConcurrentHashMap
访问性能高,可是咱们须要的是他的多线程访问共有数据的能力。性能
阻塞队列的元素获取方法
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();//获取可中断锁
try {
while (count == 0)
notEmpty.await();//队列为空,进行读线程等待
return dequeue();
} finally {
lock.unlock();
}
}
复制代码
private E dequeue() {
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();//通知写线程进行写入操做
return x;
}
复制代码
阻塞队列的元素增长方法
public void put(E e) throws InterruptedException {
checkNotNull(e);//判断元素是否为空
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();//获取可中断锁
try {
while (count == items.length)
notFull.await();//队列满时,进行写线程等待
enqueue(e);
} finally {
lock.unlock();
}
}
复制代码
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;
notEmpty.signal();//通知读线程进行操做
}
复制代码
ConcurrentLinkedQueue
上面谈及到的是多线程共享数据的容器,而这个是高并发状况下使用的。里面大量的使用了无锁的操做以及锁自旋,能够很好的保证性能问题,有兴趣的小伙伴能够去了解下。以上谈及到的就是JDK中关于并发的一些简单介绍。在我介绍完成以后,我会对底层的源码进一步讲解,有兴趣的小伙伴能够关注我~