多线程共享数据
多个线程行为一致共同操作一个数据,最经典的例子就是卖票
public class ShareData { private int num =10; public synchronized void inc(){ num++; System.out.println(Thread.currentThread().getName()+"调用inc这个方法num = "+num); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
package com.example.threadTest; /** * Description: hibernate * Created by lenovo on 2019/6/1 19:33 */ public class Ticket implements Runnable{ private ShareData shareData; public Ticket(ShareData shareData) { this.shareData = shareData; } public Ticket() { } @Override public void run() { for (int i=0;i<5;i++){ shareData.inc(); } } public static void main (String[] args){ ShareData shareData = new ShareData(); for (int i=0;i<4;i++){ new Thread(new Ticket(shareData),"Thread"+i).start(); } } }
2.多个线程行为不一致,共同操作一个数据
如果每个线程执行的代码不同这个时候就需要调用不同的Runnable对象,有两种方法实现这个Runnable对象之间的数据共享
,将共享数据封装在另外一个对象中,然后将这些对象逐一传递给各个Runnable对象 ,每一个线程对共享数据的操作方法也分配到那个对象身上去完成,这样就容易实现针对
该数据进行的各个操作的互斥和通信。
哎,先看实现再看这个总结就会恍然大悟。
在共享数据的对象里面添加不同的实现方法
package com.example.demo1; /** * Description: hibernate * Created by lenovo on 2019/6/1 19:57 */ public class MyThread implements Runnable{ private SharaData sharaData; public MyThread() { } public MyThread(SharaData sharaData) { this.sharaData = sharaData; } public static void main (String[] args){ SharaData sharaData = new SharaData(); for (int i=0;i<4;i++){ if (i%2==0){ new Thread(new MyThread(sharaData),"Thread"+i).start(); }else{ new Thread(new MyThreadDec(sharaData),"Thread"+i).start(); } } } //封装共享数据类 @Override public void run() { for (int i=0;i<5;i++){ sharaData.inc(); } } }
//
package com.example.demo1; /** * Description: hibernate * Created by lenovo on 2019/6/1 20:07 */ public class MyThreadDec implements Runnable{ //封装共享数据 private SharaData sharaData; public MyThreadDec(SharaData sharaData) { this.sharaData = sharaData; } @Override public void run() { for (int i=0;i<5;i++){ sharaData.dec(); } } }
//共享数据类
package com.example.demo1; /** * Description: hibernate * Created by lenovo on 2019/6/1 19:57 */ public class SharaData { private int num =10; public synchronized void inc(){ num++; System.out.println(Thread.currentThread().getName()+"调用inc这个方法num = "+num); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void dec(){ num++; System.out.println(Thread.currentThread().getName()+"调用inc这个方法num = "+num); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
第二种方法
将这些Runnable对象作为一个类中的内部类,共享数据作为这个外部类中的成员变量,你每一个线程对共享数据的操作方法也分配给外部类,、
以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法
package com.example.demo1; /** * Description: hibernate * Created by lenovo on 2019/6/1 20:33 */ public class Thread2 { public static void main (String[] args){ final SharaData sharaData = new SharaData(); for (int i=0;i<4;i++){ if (i%2==0){ new Thread(new Runnable() { @Override public void run() { for (int i=0;i<5;i++){ sharaData.inc(); } } },"Thread"+i).start(); }else{ new Thread(new Runnable() { @Override public void run() { for (int i=0;i<5;i++){ sharaData.dec(); } } },"Thread"+i).start(); } } } }
分析java.util.concurrent 分析线程池工厂类
package com.example.demo1; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 固定大小的线程池 */ public class Thread3 { public static void main (String[] args){ //创建一个可重用固定大小的线程池 ExecutorService pool = Executors.newFixedThreadPool(2); //创建实现了Runnable接口的对象,Thread对象当然也实现了Runnable接口 MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); MyThread t4 = new MyThread(); MyThread t5 = new MyThread(); //将线程放入池中进行执行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); //关闭线程池 pool.shutdown(); } }
pool-1-thread-1正在执行 pool-1-thread-1正在执行 pool-1-thread-1正在执行 pool-1-thread-1正在执行 pool-1-thread-2正在执行
通过这个结果可以看出,只有两个线程在执行,我们Thread类都是在线程池中运行的,线程池在执行execute方法来执行Thread类中的run方法不管execute
执行几次,线程池始终都会使用2个线程来处理,不会再去创建其他线程来处理run方法,这就是固定大小线程池。
单任务连接池
//创建一个可重用固定大小的线程池 //ExecutorService pool = Executors.newFixedThreadPool(2); ExecutorService pool = Executors.newSingleThreadExecutor(); //创建实现了Runnable接口的对象,Thread对象当然也实现了Runnable接口
pool-1-thread-1正在执行 pool-1-thread-1正在执行 pool-1-thread-1正在执行 pool-1-thread-1正在执行 pool-1-thread-1正在执行
从执行结果可以看出,单任务线程再执行execute()方法来执行Thread类中的run方法,不管exceute执行几次,线程池始终这都会使用单个线程来处理、。
、
可变连接池
//创建一个可重用固定大小的线程池 //ExecutorService pool = Executors.newFixedThreadPool(2); // ExecutorService pool = Executors.newSingleThreadExecutor(); ExecutorService pool = Executors.newCachedThreadPool(); //创建实现了Runnable接口的对象,Thread对象当然也实现了Runnable接口
pool-1-thread-1正在执行 pool-1-thread-3正在执行 pool-1-thread-2正在执行 pool-1-thread-4正在执行 pool-1-thread-5正在执行
运行结果看出,可变任务线程池再执行Thread类中的run 方法这里的execute执行多次就会创建出多个线程来处理Thread类中的run方法,所有我们看到连接池
会根据执行情况在程序运行时创建多个线程来处理,这里就是可变连接池的特点
延迟连接池
package com.example.demo1; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * 固定大小的线程池 */ public class Thread3 { public static void main (String[] args){ //创建一个可重用固定大小的线程池 //ExecutorService pool = Executors.newFixedThreadPool(2); // ExecutorService pool = Executors.newSingleThreadExecutor(); // ExecutorService pool = Executors.newCachedThreadPool(); ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); //创建实现了Runnable接口的对象,Thread对象当然也实现了Runnable接口 MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); MyThread t4 = new MyThread(); MyThread t5 = new MyThread(); //将线程放入池中进行执行 pool.execute(t1); pool.execute(t2); pool.execute(t3); //使用定时执行风格的执行方法 pool.schedule(t4,10,TimeUnit.MILLISECONDS);//t4在10s后执行 pool.schedule(t5,10,TimeUnit.MILLISECONDS);//t5在10s后执行 //关闭线程池 pool.shutdown(); } }
ExecuteService 执行器服务
package com.example.demo1; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * 固定大小的线程池 */ public class Thread3 { public static void main (String[] args){ //创建一个可重用固定大小的线程池 ExecutorService executorService = Executors.newFixedThreadPool(10); // ExecutorService pool = Executors.newSingleThreadExecutor(); // ExecutorService pool = Executors.newCachedThreadPool(); // ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); //创建实现了Runnable接口的对象,Thread对象当然也实现了Runnable接口 executorService.execute(new Runnable() { @Override public void run() { System.out.println("Asynchronous task"); } }); //线程池关闭 executorService.shutdown(); } }
上面代码首先使用了newFixedThreadPoll()工厂方法创建了一个ExecutoService这里创建了一个10个线程的执行任务的线程池,然后讲一个Runnablle接口的匿名实现类
传递给execute()方法这刚导致Executor中的某个线程执行Runnable 这里可以看成一个任务分派,任务分派我们可以理解为一个线程将一个任务委派给ExecutorService去
异步执行,一旦该线程将任务为派给ExecutorService该线程将继续他自己的执行,独立于该任务的执执行。
ExecutorService的实现
ExecutorService 是一个接口,如果你想要使用它吗,就要去使用它的实现类之一
ThreadPollExecutor
ScheduledThreadPoolExecutor
Executor 的创建步骤:
ExecutorService executorService = Executors.newFixedThreadPool(10); // ExecutorService pool = Executors.newSingleThreadExecutor(); // ExecutorService pool = Executors.newCachedThreadPool(); // ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
ExecutorService 的使用
有几种不同的方法来讲任务委托给ExecutorService来执行
execute(Runnable)
submit(Runnable)
submit(Callable)
invokeAll()
invokeAny()
execute(Runnable)的使用方法
package com.example.demo1; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * 固定大小的线程池 */ public class Thread3 { public static void main (String[] args){ //创建一个可重用固定大小的线程池 // ExecutorService executorService = Executors.newFixedThreadPool(10); ExecutorService executorService = Executors.newSingleThreadExecutor(); // ExecutorService executorService = Executors.newCachedThreadPool(); // ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2); //创建实现了Runnable接口的对象,Thread对象当然也实现了Runnable接口 executorService.execute(new Runnable() { @Override public void run() { System.out.println("Asynchronous task"); } }); //线程池关闭 executorService.shutdown(); } }
submit(Runnable)的使用方法 也要求一个Runnable实现类,但它返回一个Future对象,这个Future对象可以用来检查Runnable是否已经执行完毕
package com.example.demo1; import java.util.concurrent.*; /** * 固定大小的线程池 */ public class Thread3 { public static void main (String[] args) throws ExecutionException, InterruptedException { //创建一个可重用固定大小的线程池 // ExecutorService executorService = Executors.newFixedThreadPool(10); ExecutorService executorService = Executors.newSingleThreadExecutor(); // ExecutorService executorService = Executors.newCachedThreadPool(); // ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2); //创建实现了Runnable接口的对象,Thread对象当然也实现了Runnable接口 Future future = executorService.submit(new Runnable() { @Override public void run() { System.out.println("Asynchronous task"); } }); future.get();//获得执行完run方法后的返回值,这里使用的Runnable所以这里没有返回值,返回的是null /* executorService.execute(new Runnable() { @Override public void run() { System.out.println("Asynchronous task"); } });*/ //线程池关闭 executorService.shutdown(); } }
submit(Calable) 方法类似于submit(Runnable)方法,除了他所要求的参数类型之外,Callable实例除了它的call()得到能够返回一个结果之外和一个Runable很相像,Rannable.run()
不能够返回一个结果,Callable的结果可以通过submit(Callable) 方法返回的Future对象进行获取。
public class Thread3 { public static void main (String[] args) throws ExecutionException, InterruptedException { //创建一个可重用固定大小的线程池 // ExecutorService executorService = Executors.newFixedThreadPool(10); ExecutorService executorService = Executors.newSingleThreadExecutor(); // ExecutorService executorService = Executors.newCachedThreadPool(); // ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2); //创建实现了Runnable接口的对象,Thread对象当然也实现了Runnable接口 Future future = executorService.submit(new Callable() { @Override public Object call() throws Exception { System.out.println("Asynchronous task"); return "Callabled Result"; } }); System.out.println("Futural.get() = "+future.get()); executorService.shutdown();
}
Asynchronous task Futural.get() = Callabled Result
能拿到结果的返回值,这个就是很好的结果了
invokeAny() 这个方法要求一系列的Callable或者其子接口的实例对象,调用这个方法并不会返回一个Future,但它返回其中一个Callable对象的结果
无法保证返回的是哪个Callable的结果,只能表明其中一个以执行结束
如果其中一个任务执行结束,其他Callble将被取消
public class Thread3 { public static void main (String[] args) throws ExecutionException, InterruptedException { //创建一个可重用固定大小的线程池 // ExecutorService executorService = Executors.newFixedThreadPool(10); ExecutorService executorService = Executors.newSingleThreadExecutor(); // ExecutorService executorService = Executors.newCachedThreadPool(); // ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2); //创建实现了Runnable接口的对象,Thread对象当然也实现了Runnable接口 HashSet<Callable<String>> callables = new HashSet<>(); callables.add(new Callable<String>() { @Override public String call() throws Exception { return "Test 1"; } }); callables.add(new Callable<String>() { @Override public String call() throws Exception { return "Test 2"; } }); callables.add(new Callable<String>() { @Override public String call() throws Exception { return "Test 3"; } }); String result = executorService.invokeAny(callables); System.out.println("result="+result); executorService.shutdown(); }
result=Test 1
invokeAll() 这个方法将调用你在集合中传给ExecutorService 所有的Callabld对象 invokleAll()返回一系列的Future 对象,通过他们你们可以获取每一个Callabled的执行结果
记住,一个任务可能会由一个异常而结束,因而他可能没有成功,无法通过一个Future对象我们是两种结束中的哪一种
public class Thread3 { public static void main (String[] args) throws ExecutionException, InterruptedException { //创建一个可重用固定大小的线程池 // ExecutorService executorService = Executors.newFixedThreadPool(10); ExecutorService executorService = Executors.newSingleThreadExecutor(); // ExecutorService executorService = Executors.newCachedThreadPool(); // ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2); //创建实现了Runnable接口的对象,Thread对象当然也实现了Runnable接口 HashSet<Callable<String>> callables = new HashSet<>(); callables.add(new Callable<String>() { @Override public String call() throws Exception { return "Test 1"; } }); callables.add(new Callable<String>() { @Override public String call() throws Exception { return "Test 2"; } }); callables.add(new Callable<String>() { @Override public String call() throws Exception { return "Test 3"; } }); List<Future<String>> futures= executorService.invokeAll(callables); for (Future<String> future:futures){ System.out.println("Future.get="+future.get()); } executorService.shutdown();
Future.get=Test 1 Future.get=Test 2 Future.get=Test 3
Executors 关闭
使用shutdown shutdownNow 可以关闭线程
shutdown() 只能将空闲的线程interrupt()了,shutdown()之前提交的任务可以继续执行到结束,shutdownNow()是interrupt所有的线程因此大部分线程
将立刻被中断,之所以是大部分而不是全部是因为interrupt()方法能力有限。
ThreadPoolExecutor 线程池执行者
java.util.Concurrent.ThreadPoolExecutor 是ExecutorService接口的实现ThreadPoolExecuitor使用内部池中的线程执行给定的任务(Callable 或者Runnable)
里面有连个方法 corePoolSize
MaxMumPoolSize
当一个任务委托给线程池时,如果池中线程数量低于corePoolSize 一个新的线程将被创建,即使池中可能存有空闲线程,如果内部任务队列已满,而且有至少corePoolSize正在
运行,但是运行线程的数量低于maxMumpoolSize 一个新的线程将被创建去执行该任务。
package com.example.demo1; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * Description: hibernate * Created by lenovo on 2019/6/1 22:05 */ public class Thread4 { public static void main (String[] args){ int corePoolSize = 5; int maxPoolSize = 10; long keepAliveTime = 5000; new ThreadPoolExecutor( corePoolSize, //池中所保存的线程是 maxPoolSize, //池中允许的最大线程数 keepAliveTime, //线程数大于核心线程数时,此为终止前多余的空闲线程等待新任务的最长时间 TimeUnit.MILLISECONDS, //参数的时间单位 new LinkedBlockingQueue<Runnable>() //执行前用于保持任务的队列,次队列仅保持由execute方法 //提交的Runnable任务。 ); } }
ScheduledPoolExecutor 定时线程池执行者
java.util.concurrent.ScheduledExecutorService 是一个ExecutorService 他能够将任务延后执行,或者间隔固定时间多次执行。任务由一个工作者线程一步之幸,而不是由
交给任务给ScheduledExecutorService的那个线程执行。
package com.example.demo1; import ch.qos.logback.core.util.ExecutorServiceUtil; import com.sun.org.apache.xalan.internal.utils.FeatureManager; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * Description: hibernate * Created by lenovo on 2019/6/2 7:07 */ public class Thread5 { public static void main (String[] args){ ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); scheduledExecutorService.schedule(new Callable() { @Override public Object call() throws Exception { return "Called"; } },5, TimeUnit.SECONDS);//5秒后执行 scheduledExecutorService.shutdown(); } }
首先一个内置5个线程 的SchedualExecutorService被创建,之后一个Callable接口的匿名类实例被创建,然后传递给schedual()方法后边的俩参数定义了Callable将在
5秒之后被执行。
SchedualExecutorService的实现
SchedualExecutorService是一个接口
SchedualExecutorService的使用
schedual(Callable task,long dely,TimeUnite timeunite)
schedual(Runnable,long initialDely,long period,TimeUnit timeunit)
schedualAtFixedRate(Rannable,long initDely,long peiod ,TimeUnit timeunit)
schedualWithFixedDely(Runnable,long initialDely,long period,TimeUnit timenit)
schedual(Runnable,long initialDely,long period,TimeUnit timeunit)
package com.example.demo1; import ch.qos.logback.core.util.ExecutorServiceUtil; import com.sun.org.apache.xalan.internal.utils.FeatureManager; import java.util.concurrent.*; /** * Description: hibernate * Created by lenovo on 2019/6/2 7:07 */ public class Thread5 { public static void main (String[] args){ ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); ScheduledFuture scheduledFuture = scheduledExecutorService.schedule(new Callable() { @Override public Object call() throws Exception { System.out.println("Executed"); return "Called"; } },5, TimeUnit.SECONDS);//5秒后执行 try { System.out.println("result"+scheduledFuture.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } scheduledExecutorService.shutdown(); } }
schedual(Runnable,long initialDely,long period,TimeUnit timeunit)
这个方法规划一个任务将被定期执行,改任务将会在首个initialDely之后执行,然后每个period之后重复执行,如果给定任务的执行跑出了异常,改任务将不再执行
如果没有任何异常的话,这个任务将会持续循环执行到SchedualExceptionService被关闭
如果一个任务占用了比计划的时间间隔更长的时候,下一次执行将在当前执行结束执行草开始,计划任务在同一时间不会有多个线程同时执行。
schedualAtFixedRate(Runnable,long initialDely,long period,TimeUnit timeunit)
这一方法规划一个任务将被定期执行,该任务将会在首个initnialDely之后得到执行,然后每个period时间之后重复执行,如果给定任务的执行抛出了异常,该任务将不再执行、
如果没有任何异常,这个任务将会持续循环执行到SchedualExecutorService被关闭
如果一个任务占用了比计划的时间间隔更长的时间的时候,下一次执行将在当前执行结束执行才开始,几乎任务在同一时间不会有多个线程同时执行。
schedualWithFixedDely(Rannable ,long initialDely,long period,TimeUnite timeunite)
除了period 有不同的解释之外这个方法和schedaulFixedRate()非常像,schedualAtFixedRate()方法中peiod被解释为前一个执行的开始和下一个执行的开始之间的间隔时间
而在本方法中period被解释为前一个执行的结束,和下一个执行的开始的间隔,而不是执行开始之间的间隔。
SchedualExecutorService之间的关闭
shutdown() shutdownNow()
在你使用结束后需要把它关闭掉,否则他将会导致JVM继续运行,即使所有其他线程已经全被关闭
ForkJoinPool 合并和分叉 线程池
ForkJoinPool在java 7中被引入,他和ExecutorService很像,他可以很方便的把任务分成几个更小的任务,这些分裂出来的任务也将会提交给ForkJoinPool
任务可以继续分割成小任务,这些子任务可以被并发执行。每一个子任务可以有不同的cpu并行执行,或者被同一个cpu上的不同线程执行,只有当给的任务过大、
把它分割成几个子任务才有意义,把任务分割成几个子任务有一定的开销,因此对于小型任务,这个分割的消耗可能比每个子任务并发执行 执行的消耗还要大
合并就是当所有子任务执行结束后,将执行结果合并到同一个结果中。,如果这个子任务没有返回值,只需要等待其他子任务执行完毕,也就不需要结果的合并。
两种任务一种是有返回值的任务,另外一种是没有返回值的任务 RecursiveAction RecursiveTask
package com.example.demo2; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.RecursiveAction; /** * Description: hibernate * Created by lenovo on 2019/6/2 8:47 */ public class MyRecursiveAction extends RecursiveAction { private long workload =0; public MyRecursiveAction(long workload) { this.workload = workload; } @Override protected void compute() { //如果工作超过门槛,把任务分解成更小的任务 if (this.workload>16){ System.out.println("splitting workLoad"+this.workload); ArrayList<MyRecursiveAction> subTasks = new ArrayList<>(); subTasks.addAll(creatSubtasks()); for (RecursiveAction subTask:subTasks ){ subTask.fork(); } } else{ System.out.println("Doing workLoad myself: "+this.workload); } } private List< MyRecursiveAction> creatSubtasks() { ArrayList<MyRecursiveAction> subTasks = new ArrayList<>(); MyRecursiveAction subTask1 = new MyRecursiveAction(this.workload / 2); MyRecursiveAction subTask2 = new MyRecursiveAction(this.workload / 2); subTasks.add(subTask1); subTasks.add(subTask2); return subTasks; } }
package com.example.demo2; import java.util.concurrent.ForkJoinPool; /** * Description: hibernate * Created by lenovo on 2019/6/2 8:58 */ public class MyForkJoinPool { public static void main (String[] args){ //创建一个并行级别为4的forkJoinPool ForkJoinPool forkJoinPool = new ForkJoinPool(); //创建一个没有返回值的任务 MyRecursiveAction myRecursiveAction = new MyRecursiveAction(24); //ForkJoinPool执行任务 forkJoinPool.invoke(myRecursiveAction); } }
splitting workLoad24 Doing workLoad myself: 12 Doing workLoad myself: 12
RecurSiveTask 是一种会返回结果的任务,他可以将自己的工作分割为若干更小的任务,并将这些子任务的执行结果合并到一个集合结果,可以有结果水平的分割和合并、
package com.example.demo2; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.RecursiveTask; /** * Description: hibernate * Created by lenovo on 2019/6/2 9:08 */ public class MyRecurSiveTask extends RecursiveTask { private long workLoad =0; public MyRecurSiveTask(long workLoad) { this.workLoad = workLoad; } @Override protected Object compute() { if (this.workLoad>16){ System.out.println("spling workLoad" +this.workLoad); ArrayList<MyRecurSiveTask> subTasks = new ArrayList<>(); subTasks.addAll(creatSubTasks()); for (MyRecurSiveTask subTask : subTasks){ subTask.fork(); } long result =0; for (MyRecurSiveTask subTask:subTasks){ result += (long) subTask.join(); } return result; }else{ System.out.println("Doing workLoad myself:"+this.workLoad); return workLoad*3; } } private List< MyRecurSiveTask> creatSubTasks() { ArrayList<MyRecurSiveTask> subTasks = new ArrayList<>(); MyRecurSiveTask subTask1 = new MyRecurSiveTask(this.workLoad / 2); MyRecurSiveTask subTask2 = new MyRecurSiveTask(this.workLoad / 2); subTasks.add(subTask1); subTasks.add(subTask2); return subTasks; } }
package com.example.demo2; import java.util.concurrent.ForkJoinPool; /** * Description: hibernate * Created by lenovo on 2019/6/2 8:58 */ public class MyForkJoinPool { public static void main (String[] args){ //创建一个并行级别为4的forkJoinPool ForkJoinPool forkJoinPool = new ForkJoinPool(4); //创建一个没有返回值的任务 // MyRecursiveAction myRecursiveAction = new MyRecursiveAction(24); //创建一个有返回值的任务 MyRecurSiveTask myRecurSiveTask = new MyRecurSiveTask(128); //ForkJoinPool执行任务 long mergeResult = (long) forkJoinPool.invoke(myRecurSiveTask); System.out.println("mergeResult"+mergeResult); } }
ForkJoinPool.invoke 方法的调用来获取最终的执行结果
并发队列,阻塞队列
常用的并发队列有阻塞队列和非阻塞队列,前者使用锁实现,后者使用CAS非阻塞算法实现
阻塞队列 (Bloking Queue) java.util.concurrent 包下的重要数据结构 Bloking Queue 提供了线程安全的队列访问方式,当阻塞队列进行插入数据时,如果队列已满,线程将会阻塞等待直到队列非满,从阻塞队列取数据时,如果队列已空,线程将会阻塞等待直到队列非空,并发包下的很多高级同步类的实现都是基于BlokingQueue实现的
BlokingQueue通常用于一个线程生产对象,而另外一个线程消费这些对象的场景。一个线程将会持续生产新对象并将其插入到队列之中,直到队列达到他所能容纳的零界点、之后就会产生阻塞,直到负责消费的线程从队列中拿走一个对象,如果消费线程从空的队列中提取对象,这个消费线程将会处于阻塞状态,直到一个生产线程把一个对象丢进队列。
阻塞队列提供了4种处理方法
方法/处理方法 | 抛出异常 | 返回特殊值 | 一直阻塞 | 超时退出 |
插入方法 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除方法 | remove() | poll() | take() | poll(time,unit) |
检查方法 | element() | peek() | 不可用 | 不可用 |
四组不同的行为方式解释
抛异常:如果试图的操作无法立即执行,抛出一个异常
特定值:如果试图的操作无法立即执行,返回一个特定的值(常是true /false)
阻塞:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行
超时:如果试图的操作无法立即执行 该方法调用将会发生阻塞,直到能够执行,单等待时间不会超过给定值,返回一个特定值已告知该操作是否成功。(true/false)
无法向一个BlockingQuqu中插入null,如果你试图插入null BlockingQueue将会抛出一个nullPointException.
公平锁 :在并发环境中每一个线程在获取锁时会先查看此锁维护的等待队列,如果为空 或者当前线程是等待的第一个就占有锁,否则就会加入等待队列汇中
以后会按FIFO的规则从队列中取到自己。
ArrayBlockingQeue方法,如果队列满则返回false,否则返回true
非公平锁