目录
1.Fork/Join 框架
工作密取: A线程、B线程分别执行5个任务,A执行完5个之后发现B还没执行完,就帮助B执行。
思想: 分而治之,大任务拆分(fork)成多个小任务,在进行join的过程。
实现: ForkTask抽象类下的两个抽象类:
RecursiveTask:任务有返回值
RecursiceAction:任务没有返回值
例子: 同步方法带返回值的例子,计算4000个2的和
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
class ForkJoinTest extends RecursiveTask<Integer>{
private static final int THRESHOLD=100;
private int []src;//统计的数据
private int formIndex;//开始下标
private int endIndex;//结束下标
public ForkJoinTest(int []src,int formIndex,int endIndex) {
this.src=src;
this.formIndex=formIndex;
this.endIndex=endIndex;
}
@Override
protected Integer compute() {
//判断是否满足条件
if (endIndex-formIndex<THRESHOLD) {
//满足,进行小任务计算
int sum=0;
for (int i =formIndex;i<=endIndex;i++) {
sum+=src[i];
}
return sum;
}else{//不满足,任务拆分
int mid=(formIndex+endIndex)>>1;
ForkJoinTest left=new ForkJoinTest(src,formIndex,mid);
ForkJoinTest right=new ForkJoinTest(src,mid+1,endIndex);
//进行整合,递交给任务池
invokeAll(left,right);
return left.join()+right.join();
}
}
}
public class ThreadStudy {
public static void main(String[] args) {
int src[]=new int[4000];//初始化
for (int i = 0; i < src.length; i++) {
src[i]=2;
}
//任务池
ForkJoinPool forkJoinPool=new ForkJoinPool();
//自己写的任务
ForkJoinTest task=new ForkJoinTest(src, 0, 3999);
//提交给任务池
forkJoinPool.invoke(task);
System.out.println(task.join());
}
}
2.CountDownLatch使用示例
作用: 一个线程等待其他的线程完成工作以后在执行。
注意:扣除点和线程数可以不同。
实验内容: 5个线程有6个扣除点,主线程等初始化完成后执行。
import java.util.concurrent.CountDownLatch;
public class ThreadStudy {
//6个扣除点
static CountDownLatch latch=new CountDownLatch(6);
//初始化线程
private static class InitThread implements Runnable{
public void run() {
System.out.println("Thread_"+Thread.currentThread().getId()+"ready");
latch.countDown();//初始化工作完成了
//此时初始化线程可以继续做自己的工作
System.out.println("Thread_"+Thread.currentThread().getId()+"readyEnd");
}
}
//业务线程
private static class BusinessThread implements Runnable{
public void run() {
try {
//等待初始化线程完成
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//业务线程自己的工作
for (int i = 0; i < 5; i++) {
System.out.println("Thread_"+Thread.currentThread().getId()+"working");
}
System.out.println("Thread_"+Thread.currentThread().getId()+"end");
}
}
public static void main(String[] args) throws InterruptedException {
//同一个线程 扣除两个
new Thread(()->{
latch.countDown();
latch.countDown();
}).start();
new Thread(new BusinessThread()).start();
//扣除四个
for (int i = 0; i < 4; i++) {
new Thread(new InitThread()).start();
}
//不一定是一个线程可以await,此时让主线程await
latch.await();
System.out.println(Thread.currentThread().getName()+"done");
}
}
输出:
某次结果1:
Thread_15ready
Thread_15readyEnd
Thread_14ready
Thread_14readyEnd
Thread_13ready
Thread_13readyEnd
Thread_12ready
Thread_12readyEnd
maindone //前面初始化工作做完了(扣除点已全部扣除),Main线程可以继续
Thread_11working//业务线程工作
Thread_11working//业务线程工作
Thread_11working//业务线程工作
Thread_11working//业务线程工作
Thread_11working//业务线程工作
Thread_11end//业务线程结束
某次结果2:
Thread_12ready
Thread_14ready
Thread_14readyEnd
Thread_13ready
Thread_15ready
Thread_15readyEnd
Thread_12readyEnd
Thread_11working
Thread_11working
Thread_11working
Thread_11working
Thread_11working
Thread_11end
Thread_13readyEnd //只要扣除点扣完了,就会通知业务线程和main线程,init线程做自己的工作
maindone
3.CyclicBarrier使用示例
作用: 让一组线程达到某个屏障,被阻塞,一直到组内最后一个线程达到屏障时,屏障开放,所有被阻塞的线程会继续运行。
- 例子1:Thread-0、a、z三个线程都到达屏障后,继续运行
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class ThreadStudy {
//三个线程都到达屏障,屏障开放
private static CyclicBarrier cyclicBarrier=new CyclicBarrier(3);
private static class TestThread implements Runnable{
String name;
public TestThread(String name) {
this.name=name;
}
@Override
public void run() {
Thread.currentThread().setName(name);
try {
//休眠的时间,模拟业务
int time=1000+Integer.valueOf(name.toCharArray()[0])*10;
Thread.currentThread().sleep(time);
System.out.println(time+"after,Thread-" +Thread.currentThread().getName()+" is running");
cyclicBarrier.await();
System.out.println("Thread-" +Thread.currentThread().getName()+" end");
} catch (InterruptedException |BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
new Thread(new TestThread("0")).start();
new Thread(new TestThread("z")).start();
new Thread(new TestThread("a")).start();
}
}
输出:先各自运行
再一同输出await之后的语句
- 例子2:CyclicBarrier(int parties, Runnable barrierAction)方法
修改CyclicBarrier:
//三个线程都到达屏障,屏障开放,barrierAction定义的任务会执行
private static CyclicBarrier cyclicBarrier=new CyclicBarrier(3,()->{
System.out.println("after 0 a z ");
});
输出:
4.CountDownLatch和CyclicBarrier比较
(1)CountDownLatch由后面的其他线程决定,CyclicBarrier由任务本身的几个线程决定
(2)CountDownLatch放行条件>=线程数,CyclicBarrier放行条件=线程数
5.Semaphare实现数据库连接池
作用: 控制同时访问某个特定资源的线程数量,用在流量控制
例子:
class DpPoolSemaphore {
//数据库连接池的数量
private final static int POOL_SIZE=10;
//可用数据库连接,已用数据库连接
private final Semaphore usefull,useless;
public DpPoolSemaphore(){
this.usefull=new Semaphore(POOL_SIZE);
this.useless=new Semaphore(0);
}
//存放数据库连接
private static LinkedList<Connection> pool=new LinkedList<>();
static{
for (int i = 0; i < POOL_SIZE; i++) {
pool.addLast(new MyConnection());
}
}
//归还连接
public void returnConnect(Connection connection)throws InterruptedException{
if (connection!=null) {
useless.acquire();//已用连接-1
synchronized (pool) {
pool.addLast(connection);
}
usefull.release();//可用连接释放资源
}
}
//拿连接
public Connection takeConnection(Connection connection)throws InterruptedException{
usefull.acquire();//获取可用数据连接
Connection conn;
synchronized (pool) {
conn=pool.removeFirst();
}
useless.release();//释放已用连接,已用数据连接加一
return conn;
}
}
6.Exchange使用示例
作用: 两个线程间数据交换。
例子:交换两个线程的int数据
import java.util.concurrent.Exchanger;
public class ThreadStudy {
//三个线程都到达屏障,屏障开放,barrierAction定义的任务会执行
private static Exchanger<Integer> exchanger=new Exchanger<>();
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
int num1=1;
try {
System.out.println(Thread.currentThread().getName()+"-----"+num1);
Thread.currentThread().sleep(1000);
//先到达这个位置,阻塞,等待与它交换的线程到达之后进行交换
num1=exchanger.exchange(num1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-----"+num1);
}).start();
new Thread(()->{
int num1=2;
try {
System.out.println(Thread.currentThread().getName()+"-----"+num1);
Thread.currentThread().sleep(2000);
num1=exchanger.exchange(num1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-----"+num1);
}).start();
}
}
输出:
Thread-0-----1
Thread-1-----2
Thread-1-----1
Thread-0-----2