一:CountDownLatch
(等待多线程完成)
//构造入参2。这个参数表示需要计数2次,这个CDL才结束
CountDownLatch c = new CountDownLatch(2);
//计数 这个例子中总共需要调用两次countDown(),计数才结束
c.countDown()
//在主线程中调用,调用了这个方法后如果c没有计数到0则阻塞,直到计数为0,唤醒线程
c.await()
代码:
CountDownLatch c = new CountDownLatch(2);
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
System.out.println("线程1开始执行!");
Thread.sleep(3000);
System.out.println("线程1结束执行!");
c.countDown();
} catch (InterruptedException e) {
c.countDown();
}
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
try {
System.out.println("线程2开始执行!");
Thread.sleep(5000);
System.out.println("线程2结束执行!");
c.countDown();
} catch (InterruptedException e) {
c.countDown();
}
}
});
t1.start();
t2.start();
try {
System.out.println("开始等待线程1、2结束");
c.await();
System.out.println("线程1、2结束");
} catch (InterruptedException e) {
}
二:CyclicBarrier
让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被阻塞的线程才能执行下去。
CyclicBarrier c = new CyclicBarrier(3);
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
System.out.println("线程1开始执行!");
Thread.sleep(3000);
System.out.println("线程1结束执行!");
c.await();
} catch (Exception e) {
}
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
try {
System.out.println("线程2开始执行!");
Thread.sleep(5000);
System.out.println("线程2结束执行!");
c.await();
} catch (Exception e) {
}
}
});
t1.start();
t2.start();
System.out.println("开始等待线程1、2结束");
c.await();
System.out.println("线程1、2结束");
三:Semaphore
Semaphore(信号量)是用来控制同时访问特定资源的线程数量。
Semaphore 的构造方法需要传入一个参数,如 new Semaphore(10),
表示最多有10个线程可以获取到信号量,10个之后的线程再尝试获取时就会被阻塞。
获取信号量使用:s.acquire()方法;
释放信号量使用:s.release()方法。
只有前边的线程释放掉后,后面的线程(10个之后)才能被唤醒,重新获取信号量。它可以用来控制同时 运行的线程的数目。
private static Connection instance = new Connection();
private Semaphore semaphores = new Semaphore(10,true);
private int connections = 0;
private Connection() {
}
public static Connection getInstance() {
return instance;
}
public void connect() {
try {
semaphores.acquire();
doConnect();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphores.release();
}
}
private void doConnect() {
synchronized (this) {
connections ++;
System.out.println("current get connections is : " + connections);
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
connections --;
System.out.println("after release current connections is : " + connections);
}
}
}
public class Test1 {
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 200; i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
Connection.getInstance().connect();
}
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.DAYS);
}
四:Exchanger
Exchanger可以用于线程间交换信息。它提供一个同步点,当两个线程都到达这个同步点时,它们的信息交换。只有一个到达时,它先等待,直到另一个线程也到达。
ExecutorService threadPool = Executors.newFixedThreadPool(2);
final Exchanger<String> exchanger = new Exchanger<String>();
threadPool.execute(new Runnable() {
public void run() {
try {
String b = exchanger.exchange("hello,anyone");
System.out.println("thread1 reviced :" + b);
} catch (Exception e) {
}
}
});
threadPool.execute(new Runnable() {
public void run() {
try {
String a = exchanger.exchange("hello,anybody");
System.out.println("thread2 reviced :" + a);
} catch (Exception e) {
}
}
});
输出:
thread2 reviced :hello,anyone
thread1 reviced :hello,anybody
五:fork/join框架
public static void main(String[] args) {
long l=System.currentTimeMillis();
ForkJoinPool forkJoinPool=new ForkJoinPool();//实现ForkJoin 就必须有ForkJoinPool的支持
ForkJoinTask<Long> task=new ForkJoinWork(0l,1000000l);
Long invoke=forkJoinPool.invoke(task);
long l1 = System.currentTimeMillis();
System.out.println("invoke = " + invoke+" time: " + (l1-l));
}
public class ForkJoinWork extends RecursiveTask<Long> {
private Long start;//起始值
private Long end;//结束值
public static final Long critical = 100000L;//临界值
public ForkJoinWork(Long start, Long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
//判断是否是拆分完毕
Long lenth = end - start;
if(lenth<=critical){
//如果拆分完毕就相加
Long sum = 0L;
for (Long i = start;i<=end;i++){
sum += i;
}
return sum;
}else {
//没有拆分完毕就开始拆分
Long middle = (end + start)/2;//计算的两个值的中间值
ForkJoinWork right = new ForkJoinWork(start,middle);
right.fork();//拆分,并压入线程队列
ForkJoinWork left = new ForkJoinWork(middle+1,end);
left.fork();//拆分,并压入线程队列
//合并
return right.join() + left.join();
}
}
}
六:
1:减少锁的粒度、范围;
2:注意加锁的顺序;
3:使用超时时间锁:trylock