建设银行网站查询房贷信息,合肥网站建设百家号,国内做网站建设好的,做食品团购去那家网站好一、Fork Join
fork join是JDK7引入的一种并发框架#xff0c;采用分而治之的思想来处理并发任务
ForkJoin框架底层实现了工作窃取#xff0c;当一个线程完成任务处于空闲状态时#xff0c;会窃取其他工作线程的任务来做#xff0c;这样可以充分利用线程来进行并行计算采用分而治之的思想来处理并发任务
ForkJoin框架底层实现了工作窃取当一个线程完成任务处于空闲状态时会窃取其他工作线程的任务来做这样可以充分利用线程来进行并行计算减少线程竞争。但是在某些情况下也会存在竞争。
Fork Join框架局限性 1.拆分任务中不应该去执行IO操作 2.任务不能检查抛出异常必须通过必要的代码来抛出异常。这个在源码中就可以体现很多地方都是通过代码主动抛出异常。 3.任务只能使用Fork和Join操作来进行同步机制如果使用了其他同步机制则在同步操作时工作线程就不能执行其他任务了。比如在Fork/Join框架中使任务进行了睡眠那么在睡眠期间内正在执行这个任务的工作线程将不会执行其他任务了。
Demo ForkJoin进行累加计算
public class MakeArray {public static final int ARRAY_LENGTH4000;//获取一个随机数的数组public static int[] makeArray(){Random rnew Random();int[] resnew int[ARRAY_LENGTH];for(int i0;iARRAY_LENGTH;i){res[i]r.nextInt(ARRAY_LENGTH*3);}return res;}
}public class SumArray {private static class SumTask extends RecursiveTaskInteger{private final static int THRESHOLDMakeArray.ARRAY_LENGTH/10;private int[] src;private int fromIndex;private int toIndex;public SumTask(int[] src, int fromIndex, int toIndex) {this.src src;this.fromIndex fromIndex;this.toIndex toIndex;}Overrideprotected Integer compute() {if(toIndex-fromIndexTHRESHOLD){//无需再拆分int count0;for(int ifromIndex;itoIndex;i){try {TimeUnit.MILLISECONDS.sleep(1);countsrc[i];} catch (InterruptedException e) {throw new RuntimeException(e);}}return count;}else{int mid(fromIndextoIndex)/2;SumTask leftnew SumTask(src,fromIndex,mid);SumTask rightnew SumTask(src,mid1,toIndex);invokeAll(left,right); //执行任务把任务添加到队列该方法中执行了forkreturn left.join()right.join(); //合并结果}}}public static void main(String[] args) {int[] srcMakeArray.makeArray();ForkJoinPool poolnew ForkJoinPool();SumTask innerFindnew SumTask(src,0,src.length-1);long startSystem.currentTimeMillis();pool.invoke(innerFind);System.out.println(The count is innerFind.join() spend time:(System.currentTimeMillis()-start) ms);}
}运行结果 采用单线程进行对比
public class SumNormal {public static void main(String[] args) {int count0;int[] srcMakeArray.makeArray();long startSystem.currentTimeMillis();for(int i0;isrc.length;i){try {TimeUnit.MILLISECONDS.sleep(1);countsrc[i];} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(The count is count spend time:(System.currentTimeMillis()-start)ms);}
} 二、countDownlatch countDownlatch也是一个java的同步工具类它通过计数器来控制线程的执行顺序。初始化时需要初始化计数器的值一般都是线程数量。每当一个线程执行完任务计数器减一当计数器为0等待的线程就可以恢复执行任务。
需注意 计数器的值不一定就是线程数量线程中可以多次调用countDown来使计数器减一。 执行减一操作后线程不一定要终止也可以继续执行任务如上图TaTd。
Demo
public class UseCountDownLatch {//计数器设置为6static CountDownLatch latchnew CountDownLatch(6);private static class InitThread implements Runnable{Overridepublic void run() {System.out.println(Thread_Thread.currentThread().getId() ready init work...);//计数器减1latch.countDown();for(int i0;i2;i){System.out.println(Thread_Thread.currentThread().getId()......continue do its work);}}}private static class BusiThread implements Runnable{Overridepublic void run() {try {//在此处会阻塞当计数器扣减为0时会被唤醒latch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}for(int i0;i3;i){System.out.println(BusiThread_Thread.currentThread().getId() do business----);}}}public static void main(String[] args) {new Thread(new Runnable() {Overridepublic void run() {try {TimeUnit.MILLISECONDS.sleep(1);System.out.println(Thread_Thread.currentThread().getId() ready init work step 1st...);latch.countDown();System.out.println(begin step 2nd....);TimeUnit.MILLISECONDS.sleep(1);System.out.println(Thread_Thread.currentThread().getId() ready init work step 2nd...);latch.countDown();} catch (InterruptedException e) {throw new RuntimeException(e);}}}).start();new Thread(new BusiThread()).start();for(int i0;i3;i){new Thread(new InitThread()).start();}try {latch.await();System.out.println(Main do ites work ...);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
运行结果
三、CyclicBarrier
CyclicBarrier可以实现让一组线程达到一个屏障Barrier时被阻塞当所有线程都到达屏障时被阻塞的线程才会继续执行 Demo
public class UseCyclicBarrier {//屏障拦截四个线程当屏障放开时会执行传入的CollectThreadprivate static CyclicBarrier barriernew CyclicBarrier(4,new CollectThread());//存储子线程的工作结果private static ConcurrentHashMapString,Long resultmapnew ConcurrentHashMap();public static void main(String[] args) {for(int i0;i3;i){new Thread(new SubThread()).start();}}private static class CollectThread implements Runnable{Overridepublic void run() {StringBuilder resnew StringBuilder();for(Map.EntryString,Long r:resultmap.entrySet()){res.append([r.getValue()]);}System.out.println(the result res);}}private static class SubThread implements Runnable{Overridepublic void run() {long idThread.currentThread().getId();resultmap.put(Thread.currentThread().getId(),id);System.out.println(Thread_id...do something);try {//在此处被屏障拦截当屏障放开后才会继续执行barrier.await();System.out.println(Thread_id...do its business);} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);}}}}结果
四、Semaphore
Semaphore的中文翻译就是信号量是用来进行流量控制的可以协调各个线程合理的使用资源。 new Semaphore(10) 来创建一个信号量值为10这里会创建一个非公平的锁的同步阻塞队列。 acquire方法信号量-1 release方法信号量1 信号量为0时再执行acquire就会阻塞直到信号量不为0时其他线程执行了release才会继续运行
1.Semaphore实现连接池
注意实现连接池时需要用两个Semaphore因为通过release归还时信号量会超出10个的限制
public class DBPoolSemaphore {private final static int POOL_SIZE10;//可用连接和已用连接private final Semaphore useful,useless;//存放数据库连接的容器private static LinkedListConnection poolnew LinkedList();public DBPoolSemaphore() {this.usefulnew Semaphore(10);this.uselessnew Semaphore(0);for(int i0;iPOOL_SIZE;i){pool.addLast(SqlConnectImpl.fetchConnection());}}//归还连接public void returnConnect(Connection connection) throws InterruptedException {if(connection!null){System.out.println(There are nowuseful.getQueueLength()threads waiting to connection useful connection: useful.availablePermits());useless.acquire();synchronized (pool){pool.addLast(connection);}useful.release();}}//获取连接public Connection getConnect() throws InterruptedException {useful.acquire();Connection connection;synchronized (pool){connectionpool.removeFirst();}useless.release();return connection;}
}public class AppTest {private static DBPoolSemaphore dbPoolnew DBPoolSemaphore();private static class BusiThread extends Thread{Overridepublic void run() {Random rnew Random();long startSystem.currentTimeMillis();try {Connection connection dbPool.getConnect();System.out.println(Thread_Thread.currentThread().getId()get db connection use time:(System.currentTimeMillis()-start)ms);TimeUnit.MILLISECONDS.sleep(100r.nextInt(100)); //模拟业务操作System.out.println(task completion,return connection);dbPool.returnConnect(connection);} catch (InterruptedException e) {throw new RuntimeException(e);}}}public static void main(String[] args) {for(int i0;i50;i){Thread threadnew BusiThread();thread.start();}}
}运行结果
2.思考
使用双信号量是为了防止信号量会超过10个的限制如果按如下的方法调用连接池
public class AppTest {private static DBPoolSemaphore dbPoolnew DBPoolSemaphore();private static class BusiThread extends Thread{Overridepublic void run() {Random rnew Random();long startSystem.currentTimeMillis();try {
// Connection connection dbPool.getConnect();
// System.out.println(Thread_Thread.currentThread().getId()
// get db connection use time:(System.currentTimeMillis()-start)ms);
// TimeUnit.MILLISECONDS.sleep(100r.nextInt(100)); //模拟业务操作
// System.out.println(task completion,return connection);dbPool.returnConnect(new SqlConnectImpl());} catch (InterruptedException e) {throw new RuntimeException(e);}}}public static void main(String[] args) {for(int i0;i50;i){Thread threadnew BusiThread();thread.start();}}
}在线程中只归还连接归还的是自己new出来的连接。如果此时是单信号量只有useful那么useful会变成60个 //单信号量public void returnConnect(Connection connection) throws InterruptedException {if(connection!null) {System.out.println(There are nowuseful.getQueueLength()threads waiting to connection useful connection: useful.availablePermits());synchronized (pool) {pool.addLast(connection);}useful.release();}}如果采用两个信号量因为useless一开始为0所以没有get连接直接归还连接时会在useless.acquire那里阻塞住可以有效的防止上面情况的发生。 //双信号量public void returnConnect(Connection connection) throws InterruptedException {if(connection!null){System.out.println(There are nowuseful.getQueueLength()threads waiting to connection useful connection: useful.availablePermits());System.out.println(1);useless.acquire(); //useless一开始为0.直接调用returnConnect会在这里阻塞住System.out.println(2);synchronized (pool){pool.addLast(connection);}useful.release();}}log中并没有2归还连接时被阻塞在useless.acquire
总之双信号量可以有效的防止可用连接溢出的情况发生。个人感觉如果是实现一个线程池线程池中的连接不能让用户通过new SqlConnectImpl()这种形式new出来SqlConnectImpl应该是对用户不可见的。对于用户来说应该只能通过getConnect来从线程池获取连接这样或许也能够避免这种问题出现。