一、同步容器
Vector、Hashtable、Collections.synchronizedXxx
每次只能有一个线程访问
当同步容器在迭代过程中被修改将会抛出ConcurrentModificationException
二、并发容器
相比同步容器极大提高
1、ConcurrentHashMap、CopyOnWriteArrayList、Queue(ConcurrentLinkedQueue、PriorityQueue)、BlockingQueue、ConcurrentSkipListMap、ConcurrentSkipListSet
2、ConcurrentHashMap
采用分段锁,任意数量读线程并发访问、读写并发访问、一定数量写线程并发发问,
size和isEmpty精确度稍低
3、CopyOnWriteArrayList
写操作时会发布一个新的副本,但会有一定的开销,迭代多于修改时适合使用
4、BlockingQueue
阻塞方法: put和take
LinkedBlockingQueue、ArrayBlockingQueue、PriorityBlockingQueue、SynchronousQueue(没有队列,生产者直接给消费者,没有中间者)
5、Deque和BlocingDeque
双端队列
public class Test {
public static void main(String[] args) {
List<Integer> arrInt = new ArrayList<>();
for (int i = 0; i < 50; i++) {
arrInt.add(i + 1);
}
final Queue<Integer> queue = new ConcurrentLinkedQueue<Integer>();
queue.addAll(arrInt);
new Thread(new Runnable() {
@Override
public void run() {
while(!queue.isEmpty()) {
System.out.println(Thread.currentThread().getName() + " ====> " + queue.poll());
}
}
}, "a").start();
new Thread(new Runnable() {
@Override
public void run() {
while(!queue.isEmpty()) {
System.out.println(Thread.currentThread().getName() + " ====> " + queue.poll());
}
}
}, "b").start();
new Thread(new Runnable() {
@Override
public void run() {
while(!queue.isEmpty()) {
System.out.println(Thread.currentThread().getName() + " ====> " + queue.poll());
}
}
}, "c").start();
new Thread(new Runnable() {
@Override
public void run() {
while(!queue.isEmpty()) {
System.out.println(Thread.currentThread().getName() + " ====> " + queue.poll());
}
}
}, "d").start();
}
}
三、同步工具类
1、闭锁 CountDownLatch
重要方法:
await() 等待计数器为0,否则一直阻塞
countDown() 计数器减一
package com.sosop.nio2;
import java.util.concurrent.CountDownLatch;
public class CloseLock {
public static void main(String[] args) throws InterruptedException {
CountDownLatch begin = new CountDownLatch(1);
CountDownLatch end = new CountDownLatch(10);
for (int i = 1; i <= 10; i++) {
new Thread(new Task(String.valueOf(i), begin, end)).start();
}
begin.countDown();
end.await();
}
}
class Task implements Runnable {
private String name;
private CountDownLatch begin;
private CountDownLatch end;
public Task(String name, CountDownLatch begin, CountDownLatch end) {
this.name = name;
this.begin = begin;
this.end = end;
}
@Override
public void run() {
try{
System.out.println(name + " is waiting ..." );
begin.await();
System.out.println(name + " is working");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
end.countDown();
}
}
}
start.countDown()
end.await()
2.FutureTask
可返回结果,通过Callable实现
三状态:等待运行 正在运行 运行结束
get会阻塞到任务完成返回结果
package com.sosop.nio2;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ClosableLock {
public static void main(String[] args) throws InterruptedException, ExecutionException {
MyTask task1 = new MyTask(10, 20);
MyTask task2 = new MyTask(99, 1);
Thread t1 = new Thread(task1);
t1.start();
Thread t2 = new Thread(task2);
t2.start();
System.out.println(task1.get());
System.out.println(task2.get());
}
}
class MyTask extends FutureTask<Integer> {
public MyTask(final int a, final int b) {
super(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return a + b;
}
});
}
}
3.信号量
Semaphore
初始化许可或证书的数量,执行操作前都必须获得许可acquir(),执行完成或使用完成后释放许可release()
package nioTest;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
public static void main(String[] args) {
Pool pool = new Pool(1);
pool.add(1);
pool.remove(2);
pool.add(2);
}
}
class Pool {
private Semaphore sem;
private Set<Integer> container;
public Pool(int size) {
container = Collections.synchronizedSet(new HashSet<Integer>());
sem = new Semaphore(size);
}
public void add(int element) {
boolean in = false;
try {
sem.acquire();
in = container.add(element);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(!in) {
sem.release();
}
}
}
public void remove(int element) {
boolean out = container.remove(element);
if(out) {
sem.release();
}
}
}
4.栅栏
CyclicBarrier
等待所有线程汇集到一个地方再往下执行
闭锁不能重置但栅栏可以重置
package nioTest;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String[] args) {
new Calculate(88).init().start();
}
}
class Calculate {
private Member[] members;
private CyclicBarrier barrier;
public Calculate(int count) {
this.members = new Member[count];
this.barrier = new CyclicBarrier(count, new Runnable() {
@Override
public void run() {
System.out.println(Calculate.this.total());
}
});
}
public void start() {
for (int i = 0; i < members.length; i++) {
new Thread(members[i]).start();
}
}
public Calculate init() {
for (int i = 0; i < members.length; i++) {
members[i] = new Member(i + 1, barrier);
}
return this;
}
public int total() {
int total = 0;
for (Member member : members) {
total += member.result();
}
return total;
}
}
class Member implements Runnable {
private int result;
private CyclicBarrier barrier;
public Member(int result, CyclicBarrier barrier) {
this.result = result;
this.barrier = barrier;
}
@Override
public void run() {
try {
this.result = this.result * 8;
System.out.println("waiting ...");
barrier.await();
System.out.println("continu ...");
} catch (InterruptedException | BrokenBarrierException e) {
return;
}
}
public int result() {
return this.result;
}
}