1. 单例模式(在内存之中永远只有一个对象)
1.1 多线程安全单例模式——不使用同步锁
1 public class Singleton {
2 private static Singleton sin=new Singleton(); ///直接初始化一个实例对象
3 private Singleton(){ ///private类型的构造函数,保证其他类对象不能直接new一个该对象的实例
4 }
5 public static Singleton getSin(){ ///该类唯一的一个public方法
6 return sin;
7 }
8 }
上述代码中的一个缺点是该类加载的时候就会直接new 一个静态对象出来,当系统中这样的类较多时,会使得启动速度变慢 。现在流行的设计都是讲“延迟加载”,我们可以在第一次使用的时候才初始化第一个该类对象。所以这种适合在小系统。
1.2 多线程安全单例模式——使用同步方法
1 public class Singleton {
2 private static Singleton instance;
3 private Singleton (){
4
5 }
6 public static synchronized Singleton getInstance(){ //对获取实例的方法进行同步
7 if (instance == null)
8 instance = new Singleton();
9 return instance;
10 }
11 }
上述代码中的一次锁住了一个方法, 这个粒度有点大 ,改进就是只锁住其中的new语句就OK。就是所谓的“双重锁”机制。
1.3 多线程安全单例模式——使用双重同步锁
1 public class Singleton {
2 private static Singleton instance;
3 private Singleton (){
4 }
5 public static Singleton getInstance(){ //对获取实例的方法进行同步
6 if (instance == null){
7 synchronized(Singleton.class){
8 if (instance == null)
9 instance = new Singleton();
10 }
11 }
12 return instance;
13 }
14
15 }
1.4 多线程安全单例模式——使用内部类的单例模式
既不用加锁,也能实现懒加载
1 public class Singleton {
2 private Singleton(){
3 System.out.println("single");
4 }
5 private static class Inner{
6 private static Singleton s = new Singleton();
7 }
8 //无论有多少次,有多少个线程在调用getsingle的时候拿到的都是同一个对象
9 private static Singleton getSingle(){
10 return Inner.s;
11 }
12 public static void main(String[] agrs){
13 Thread[] ths = new Thread[200];
14 for(int i=0; i<ths.length;i++){
15 ths[i]=new Thread(()->{
16 Singleton.getSingle();
17 });
18 }
19 Arrays.asList(ths).forEach(o->o.start());
20 }
21 }
2. 高并发——容器
2.1 有N张火车票,每张票都有一个编号,同时有10个窗口对外售票,写一个模拟程序,分析可能会产生哪些问题?重复销售,超量销售;
1 public class TicketSeller1 {
2 static List<String> tickets = new ArrayList<>();
3 //初始化,放票
4 static{
5 for(int i=0; i<10000; i++)
6 tickets.add("票编号:"+i);
7 }
8
9 public static void main(String[] args){
10 //启动10个线程不断往外卖票
11 for(int i=0;i<10;i++){
12 new Thread(()->{
13 while(tickets.size()>0){
14 System.out.println("销售了--"+tickets.remove(0));
15 }
16 }).start();
17 }
18 }
19 }
改成下面的代码还有问题吗?
1 public class TicketSeller2 {
2 //vector本身就是一个同步容器,它所有的方法都是加锁的
3 static Vector<String> tickets = new Vector<>();
4 static{
5 for(int i=0; i<10000; i++)
6 tickets.add("票编号:"+i);
7 }
8 public static void main(String[] args){
9 for(int i=0; i<10; i++){
10 new Thread(()->{
11 while(tickets.size()>0){
12 /*
13 try{
14 TimeUnit.SECONDS.sleep(10);
15 }catch(InterruptedException e){
16 e.printStackTrace();
17 }*/
18 System.out.println("销售了--"+tickets.remove(0));
19 }
20 }).start();
21 }
22 }
23 }
仍有问题,判断与操作分离了(虽然在vector中size和remove方法都是原子的);
再改进:将判断和操作放到一个原子操作里面去
1 public class TicketSeller3 {
2 static List<String> tickets = new ArrayList<>();
3 static{
4 for(int i=0; i<10000; i++)
5 tickets.add("票编号:"+i);
6 }
7
8 public static void main(String[] args){
9 //启动10个线程不断往外卖票
10 for(int i=0;i<10;i++){
11 new Thread(()->{
12 while(true){
13 synchronized (tickets){
14 if(tickets.size()<=0) break;
15 try{
16 TimeUnit.SECONDS.sleep(10);
17 }catch(InterruptedException e){
18 e.printStackTrace();
19 }
20
21 System.out.println("销售了--"+tickets.remove(0));
22 }
23 }
24 }).start();
25 }
26 }
27 }
加锁效率不高,尤其是每销售一张票都要把整个队列给锁定;
引入并发容器:
1 public class TicketSeller4 {
2 //并发容器
3 static Queue<String> tickets = new ConcurrentLinkedQueue<>();
4 static{
5 for(int i=0; i<1000; i++){
6 tickets.add("票编号:"+i);
7 }
8 }
9 public static void main(String[] args){
10 for(int i=0; i<10; i++){
11 new Thread(()->{
12 while(true){
13 //poll从头往外拿一个数据,是同步的
14 String s = tickets.poll();
15 if(s==null) break;
16 else System.out.println("销售了--"+s);
17 }
18 }).start();
19 }
20 }
21 }
if(s==null) break;虽然不是原子性的,但是我们判断以后没有对队列作修改操作,所以这里不会出错。
2.2 并发容器————ConcurrentMap
在多线程的情况下,什么样的容器效率比较高?
1 public class T_ConcurrentMap {
2 public static void main(String[] args){
3 //Map<String, String> map = new ConcurrentHashMap<>();
4 //Map<String, String> map = new ConcurrentSkipListMap<>();
5 //HashTable 默认加锁,但是效率比较低
6 Map<String, String> map = new Hashtable<>();
7 //使用HashMap,自己往上加锁:Collection.synchronizedXXX
8 //Map<String, String> map = new HashMap<>();
9 //Map<String, String> map = new TreeMap<>();
10
11 Random r = new Random();
12 Thread[] ths = new Thread[100];
13 CountDownLatch latch = new CountDownLatch(ths.length);
14 long start = System.currentTimeMillis();
15 for(int i=0; i<ths.length; i++){
16 ths[i] = new Thread(()->{
17 for(int j=0; j<10000; j++)
18 map.put("a"+r.nextInt(100000),"a"+r.nextInt(100000));
19 latch.countDown();
20 });
21 }
22 Arrays.asList(ths).forEach(o->o.start());
23 try{
24 latch.await();
25 }catch (InterruptedException e){
26 e.printStackTrace();
27 }
28
29 long end = System.currentTimeMillis();
30 System.out.println(end-start);
31 }
32 }
HashTable:669;
ConcurrentHashMap:391;
why? HashTable 往里加任何一个数据的时候都是要锁定整个对象,而HashMap,ConcurrentHashMap默认把容器分成16段,每次往容器里插数据只锁定16段里面的一段(把锁细化),两个线程往里插不同的段的数据,那么这两个线程就能并发的插入;
ConcurrentSkipListMap:649 高并发并且排序
往里插数据效率低一些,因为要排序,查数据方便很多;
总结:
1. 对于map/set的选择使用
不加锁:hashmap;treemap;linkedhashmap;
加锁:hashtable;Collection.sychronizedXXX(传一个不加锁map,返回一个加了锁的map),在并发性不是特别高的情况下可以使用上面两种;如果并发性比较高,用concurrenthashmap,如果还需要排序,就用concurrentskiplistmap;
附:Collection.sychronizedXXX用法:
1 public class T_SynchronizedList {
2 public static void main(String[] args){
3 List<String> strs = new ArrayList<>();
4 List<String> strsSync = Collections.synchronizedList(strs);
5 }
6 }
2.3 并发容器——CopyOnWrite 写时复制容器
多线程环境下,写时效率低,读时效率高,适合写少读多的环境;
比较容器效率 :
1 public class T_CopyOnWrite {
2 public static void main(String[] args){
3 List<String> lists =
4 //new ArrayList<>();//这个会出并发问题
5 //new Vector<>();
6 new CopyOnWriteArrayList<>();
7 Random r = new Random();
8 Thread[] ths = new Thread[100];
9 for(int i=0; i<ths.length; i++){
10 Runnable task = new Runnable() {
11 @Override
12 public void run() {
13 for(int j=0;j<1000;j++)
14 lists.add("a"+r.nextInt(10000));
15 }
16 };
17 ths[i] = new Thread(task);
18 }
19 runAndComputeTime(ths);
20 System.out.println(lists.size());
21 }
22 static void runAndComputeTime(Thread[] ths){
23 long s1 = System.currentTimeMillis();
24 Arrays.asList(ths).forEach(o->o.start());
25 Arrays.asList(ths).forEach(o->{
26 try{
27 o.join();
28 }catch(InterruptedException e){
29 e.printStackTrace();
30 }
31 });
32 long s2 = System.currentTimeMillis();
33 System.out.println(s2-s1);
34 }
35 }
CopyOnWriteArrayList:4853 100000
Vector:114 100000
ArrayList:97 86864(有错)
2.4 并发容器——ConcurrentLinkedQueue
常用方法:
1 public class T_ConcurrentLinkedQueue {
2 public static void main(String[] args){
3 Queue<String> strs = new ConcurrentLinkedQueue<>();
4 for(int i=0; i<10; i++){
5 //类似于add,有boolean返回值
6 strs.offer("a"+i);
7 }
8 System.out.println(strs);
9 System.out.println(strs.size());
10 System.out.println(strs.poll());//取值并删除
11 System.out.println(strs.size());
12 System.out.println(strs.peek());//只取值不删
13 System.out.println(strs.size());
14 }
15 }
2.5 并发容器——BlockingQueue
在高并发的情况下可以使用两种队列:
ConcurrentLinkedQueue:加锁式
BlockingQueue:阻塞式
LinkedBlockingQueue:
1 public class T_LinkedBlockingQueue {
2 static BlockingQueue<String> strs = new LinkedBlockingQueue<>();
3 static Random r = new Random();
4 public static void main(String[] args){
5 //生产者线程
6 new Thread(()->{
7 for(int i=0; i<100; i++){
8 try{
9 strs.put("a"+i);//使用put,如果满了,就会等待
10 }catch(InterruptedException e){
11 e.printStackTrace();
12 }
13 }
14 },"p1").start();
15 //5个消费者线程
16 for(int i=0; i<5; i++){
17 new Thread(()->{
18 for(;;){
19 try{
20 System.out.println(Thread.currentThread().getName()+"task-"+strs.take());//take如果空了,就会等待
21 }catch(InterruptedException e){
22 e.printStackTrace();
23 }
24 }
25 },"c"+i).start();
26 }
27 }
28 }
ArrayBlockingQueue:
1 public class T_ArrayBlockingQueue {
2 //有界队列
3 static BlockingQueue<String> strs = new ArrayBlockingQueue<>(10);
4 static Random r = new Random();
5 public static void main(String[] args) throws Exception{
6 for(int i=0; i<10; i++){
7 strs.put("a"+i);
8 }
9 //strs.put("aaa");//满了就会等待,程序阻塞
10 //strs.add("aaa");//队列满了会报异常
11 strs.offer("aaa");//队列满了不会报异常,也加不进去
12 //strs.offer("aaa",1, TimeUnit.SECONDS);//隔一段时间之内加不进去就不往里面加了
13 System.out.println(strs);
14 }
15 }
DelayQueue:
1 public class T_DelayQueue {
2 //加入队列的元素只有等一定的时间之后才能被消费者拿走
3 //默认按等待时间排序
4 //DelayQueue 需要实现接口
5 static BlockingQueue<MyTask> tasks = new DelayQueue<>();
6 static Random r = new Random();
7 static class MyTask implements Delayed{
8 long runningTime;
9 MyTask(long rt){
10 this.runningTime = rt;
11 }
12 public int compareTo(Delayed o){
13 if(this.getDelay(TimeUnit.MILLISECONDS)<o.getDelay(TimeUnit.MILLISECONDS))
14 return -1;
15 else if(this.getDelay(TimeUnit.MILLISECONDS)>o.getDelay(TimeUnit.MILLISECONDS))
16 return 1;
17 else
18 return 0;
19 }
20
21 @Override
22 public long getDelay(TimeUnit unit) {
23 return unit.convert(runningTime-System.currentTimeMillis(), TimeUnit.MILLISECONDS);
24 }
25
26 public String toString(){
27 return ""+runningTime;
28 }
29 }
30
31 public static void main(String[] agrs) throws InterruptedException{
32 long now = System.currentTimeMillis();
33 MyTask t1 = new MyTask(now+1000);
34 MyTask t2 = new MyTask(now+2000);
35 MyTask t3 = new MyTask(now+1500);
36 MyTask t4 = new MyTask(now+2500);
37 MyTask t5 = new MyTask(now+500);
38
39 tasks.put(t1);
40 tasks.put(t2);
41 tasks.put(t3);
42 tasks.put(t4);
43 tasks.put(t5);
44
45 System.out.println(tasks);
46
47 for(int i=0; i<5; i++){
48 System.out.println(tasks.take());
49 }
50 }
51 }
[1558935218208, 1558935218708, 1558935219208, 1558935220208, 1558935219708]
1558935218208
1558935218708
1558935219208
1558935219708
1558935220208
可以用来做定时执行任务
TransferQueue:
1 public class T_TransferQueue {
2 public static void main(String[] agrs) throws InterruptedException{
3 LinkedTransferQueue<String> strs = new LinkedTransferQueue<>();
4 new Thread(()->{
5 try{
6 System.out.println(strs.take());
7 }catch(InterruptedException e){
8 e.printStackTrace();
9 }
10 }).start();
11 //先启动几个消费者线程,生产者生产出一个产品的时候不往队列里加,
12 //首先去找有没有消费者,有消费者直接给消费者消费,没有就阻塞
13 //用在更高并发的情况下
14 strs.transfer("aaa");
15 }
16 }
SynchronusQueue:
1 public class SynchronusQueue {//没有容量的队列
2 public static void main(String[] agrs) throws InterruptedException{
3 //同步队列是一种特殊的transferQueue
4 //
5 BlockingQueue<String> strs = new SynchronousQueue<>();
6 new Thread(()->{
7 try{
8 System.out.println(strs.take());
9 }catch(InterruptedException e){
10 e.printStackTrace();
11 }
12 }).start();
13
14 //strs.put("aaa");//不报错,阻塞等待消费者消费
15 strs.add("aaa");//报错queue full
16 System.out.println(strs.size);
17 }
18 }
3. 线程池
3.1 Executor
执行器,这是一个接口,内部维护了一个方法execute负责执行一项任务,参数为Runnable,方法具体实现有我们执行,如下面的代码,既可以使用单纯的方法调用也可以新砌一个新的线程去执行Runnable的run方法;
1 public class T_MyExecutor implements Executor {
2 public static void main(String[] agrs){
3 new T_MyExecutor().execute(()->System.out.println("hello executor"));
4 }
5
6 public void execute(Runnable commend){
7 commend.run();
8 //new Thread(commend).run();
9 }
10 }
3.2 ExecutorService
代表着启动一系列的线程为用户提供服务(本质上也是一个执行器),Java8官方文档就举了一个网络接受连接池的例子(代码如下)。
1 class NetworkService implements Runnable {
2 private final ServerSocket serverSocket;
3 private final ExecutorService pool;
4
5 public NetworkService(int port, int poolSize)
6 throws IOException {
7 serverSocket = new ServerSocket(port);
8 pool = Executors.newFixedThreadPool(poolSize);
9 }
10
11 public void run() { // run the service
12 try {
13 for (;;) {
14 pool.execute(new Handler(serverSocket.accept()));
15 }
16 } catch (IOException ex) {
17 pool.shutdown();
18 }
19 }
20 }
21
22 class Handler implements Runnable {
23 private final Socket socket;
24 Handler(Socket socket) { this.socket = socket; }
25 public void run() {
26 // read and service request on socket
27 }
28 }
Callable是一个增强版的Runnable,它的call方法可以抛出异常可以有返回值,返回值放在Future对象中,我们可以使用Future对象的get方法来获得返回值。
Executors这个工具类来创建它,在这里我们可以把Executors理解为就像utils,collections的工具类,是操作Executor的一个工具类。
2.3 ThreadPool 线程池
1 public class T_ThreadPool {
2 public static void main(String[] agrs) throws InterruptedException{
3 //Executors有一些工厂方法,newFixedThreadPool创建一个个数为5的线程池
4 //ExecutorService接口是可以往里面扔任务(execute,submit)的,
5 ExecutorService service = Executors.newFixedThreadPool(5);
6 for(int i=0; i<6;i++){
7 //5个线程,6个任务
8 service.execute(()->{
9 try{
10 TimeUnit.MILLISECONDS.sleep(500);
11 }catch(InterruptedException e){
12 e.printStackTrace();
13 }
14 System.out.println(Thread.currentThread().getName());
15 });
16 }
17 System.out.println(service);
18 //ExecutorService 常用方法
19 service.shutdown();//所有任务执行完关闭
20 System.out.println(service.isTerminated());//所有任务是否执行完了
21 System.out.println(service.isShutdown());//关了并一定是执行完了,代表正在关闭的过程中
22 System.out.println(service);
23 }
24 }
执行结果:
java.util.concurrent.ThreadPoolExecutor@7ba4f24f[Running, pool size = 5, active threads = 5, queued tasks = 1(排队的任务), completed tasks = 0]
false
true
java.util.concurrent.ThreadPoolExecutor@7ba4f24f[Shutting down, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
pool-1-thread-1
pool-1-thread-3
pool-1-thread-2
pool-1-thread-5
pool-1-thread-4
pool-1-thread-1
2.4 Future
1 public class T_Future {
2 public static void main(String[] agrs) throws InterruptedException, ExecutionException{
3 //RunnableTask 不产生任何返回值
4 //new了个Callable对象并把它包装成FutureTask
5 FutureTask<Integer> task = new FutureTask<>(()->{
6 TimeUnit.MILLISECONDS.sleep(500);
7 return 1000;
8 });//相当于创建一个匿名类:new Callable(){Integer call();}}
9 //启动一个线程
10 new Thread(task).start();
11 System.out.println(task.get());//阻塞,任务执行完了返回值
12
13 ExecutorService service = Executors.newFixedThreadPool(5);
14 Future<Integer> f = service.submit(()->{
15 TimeUnit.MILLISECONDS.sleep(500);
16 return 1;
17 });
18 System.out.println(f.get());
19 System.out.println(f.isDone());//任务执行完没有啊
20 System.out.println(f.get());
21 System.out.println(f.isDone());
22 }
23 }
2.5 线程池——newFixedThreadPool
小程序:计算1-200000之间的质数
比较一个线程和多个线程的效率:
1 public class T_ParallelComputing {
2 public static void main(String[] agrs) throws InterruptedException, ExecutionException {
3 long start = System.currentTimeMillis();
4 //计算1-200000之间所有的质数
5 List<Integer> resulrs = getPrime(1,200000);
6 //方法1:使用一个线程来计算
7 long end = System.currentTimeMillis();
8 System.out.println(end-start);
9
10 //方法2:使用线程池
11 final int cpuCoreNum = 4;
12 ExecutorService service = Executors.newFixedThreadPool(cpuCoreNum);
13 //创建4个任务,继承callable接口(有返回值)
14 MyTask t1 = new MyTask(1,80000);
15 MyTask t2 = new MyTask(80000,130000);
16 MyTask t3 = new MyTask(130000,170000);
17 MyTask t4 = new MyTask(170000,200000);
18 //将4个任务扔到线程池
19 Future<List<Integer>> f1 = service.submit(t1);
20 Future<List<Integer>> f2 = service.submit(t2);
21 Future<List<Integer>> f3 = service.submit(t3);
22 Future<List<Integer>> f4 = service.submit(t4);
23
24 start = System.currentTimeMillis();
25 f1.get();
26 f2.get();
27 f3.get();
28 f4.get();
29 end = System.currentTimeMillis();
30 System.out.println(end-start);
31 }
32
33 static class MyTask implements Callable<List<Integer>> {
34 int startPos,endPos;
35
36 MyTask(int s,int e){
37 this.startPos = s;
38 this.endPos = e;
39 }
40 public List<Integer> call() throws Exception{
41 List<Integer> r = getPrime(startPos, endPos);
42 return r;
43 }
44 }
45 static boolean isPrime(int num){
46 for(int i=2;i<=num/2;i++){
47 if(num%i==0) return false;
48 }
49 return true;
50 }
51 static List<Integer> getPrime(int start,int end){
52 List<Integer> results = new ArrayList<>();
53 for(int i=start;i<=end;i++){
54 if(isPrime(i)) results.add(i);
55 }
56 return results;
57 }
58 }
输出:
2513
786
2.6 线程池——CacheThreadPool
刚开始一个线程也没有,来一个任务起一个线程,如果来一个新的任务,线程池里刚好有一个线程空闲,直接让空闲线程执行任务,否则,起一个新线程;默认情况下,线程空闲超过60s自动销毁;
1 public class T_CacheThreadPool {
2 public static void main(String[] agrs) throws InterruptedException{
3 ExecutorService service = Executors.newCachedThreadPool();
4 System.out.println(service);
5
6 for(int i=0;i<2;i++){
7 service.execute(()->{
8 try{
9 TimeUnit.MILLISECONDS.sleep(500);
10 }catch(InterruptedException e){
11 e.printStackTrace();
12 }
13 System.out.println(Thread.currentThread().getName());
14 });
15 }
16 System.out.println(service);
17 TimeUnit.SECONDS.sleep(80);
18 System.out.println(service);
19 }
20 }
运行结果:
java.util.concurrent.ThreadPoolExecutor@1540e19d[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@1540e19d[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0]
pool-1-thread-2
pool-1-thread-1
java.util.concurrent.ThreadPoolExecutor@1540e19d[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 2]
2.7 线程池——SingleThreadPool
线程池里就一个线程,保证任务顺序执行
1 public class SingleThreadPool {
2 public static void main(String[] agrs){
3 ExecutorService service = Executors.newSingleThreadExecutor();
4 for(int i=0;i<5;i++){
5 final int j = i;
6 service.execute(()->{
7 System.out.println(j+" "+Thread.currentThread().getName());
8 });
9 }
10 }
11 }
输出:
0 pool-1-thread-1
1 pool-1-thread-1
2 pool-1-thread-1
3 pool-1-thread-1
4 pool-1-thread-1
2.8 线程池——SchedulePool
与DelayQueue相对应,执行定时的任务,线程池里的线程可以复用
1 public class SchedulePool {
2 public static void main(String[] agrs){
3 ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
4 service.scheduleAtFixedRate(()->{
5 try{
6 TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
7 }catch(InterruptedException e){
8 e.printStackTrace();
9 }
10 System.out.println(Thread.currentThread().getName());
11 },0,500, TimeUnit.MILLISECONDS);
12 }
13 }
2.9 线程池——WorkStealingPool
工作窃取:有一堆任务和一堆线程,每个线程都维护一个自己的任务队列,当一个线程执行完自己队列里的任务,会去别的线程队列中“偷”未执行的任务继续执行;
1 public class WorkStealPool {
2 public static void main(String[] agrs) throws IOException {
3 ExecutorService service = Executors.newWorkStealingPool();
4 //打印cup多少核
5 System.out.println(Runtime.getRuntime().availableProcessors());
6
7 service.execute(new R(1000));
8 service.execute(new R(2000));
9 service.execute(new R(2000));
10 service.execute(new R(2000));
11 service.execute(new R(2000));
12 //由于产生的是守护线程,主线程不阻塞看不到输出
13 System.in.read();
14 }
15 public static class R implements Runnable{
16 int time;
17 R(int t){
18 this.time = t;
19 }
20 public void run(){
21 try{
22 TimeUnit.MILLISECONDS.sleep(time);
23 }catch (InterruptedException e){
24 e.printStackTrace();
25 }
26 System.out.println(time+" "+Thread.currentThread().getName());
27 }
28 }
29 }
2.10 线程池——ForkJoinPool
如果有一项特别难以完成的大任务,可以把大任务切分成小的任务(Fork),最后合并小任务(Join);
1 public class ForkJoinPool2 {
2 static int[] nums = new int[1000000];
3 static final int MAX_NUM = 50000;
4 static Random r = new Random();
5 //求和
6 static {
7 for(int i=0; i<nums.length;i++){
8 nums[i]=r.nextInt(100);
9 }
10 System.out.println(Arrays.stream(nums).sum());
11 }
12
13 static class AddTask extends RecursiveAction{
14 int start,end;
15 AddTask(int s, int e){
16 start = s;
17 end = e;
18 }
19 protected void compute(){
20 if(end-start<=MAX_NUM){
21 long sum = 0L;
22 for(int i=start;i<end;i++){
23 sum+=nums[i];
24 }
25 System.out.println("from:"+start+"to:"+end+"="+sum);
26 }else{
27 int middle = start+(end-start)/2;
28 AddTask subTask1 = new AddTask(start,middle);
29 AddTask subTask2 = new AddTask(middle,end);
30 subTask1.fork();
31 subTask2.fork();
32 }
33 }
34 }
35 public static void main(String[] agrs) throws IOException{
36 ForkJoinPool fjp = new ForkJoinPool();
37 AddTask task = new AddTask(0,nums.length);
38
39 fjp.execute(task);
40 System.in.read();
41 }
42 }
49508417
from:593750to:625000=1543717
from:468750to:500000=1548821
from:843750to:875000=1548865
from:968750to:1000000=1543900
from:718750to:750000=1539386
from:437500to:468750=1547593
from:812500to:843750=1538471
from:687500to:718750=1540626
from:562500to:593750=1545775
from:937500to:968750=1546144
from:406250to:437500=1550529
from:781250to:812500=1540313
from:218750to:250000=1556540
from:656250to:687500=1547825
from:93750to:125000=1545292
from:156250to:187500=1546528
from:531250to:562500=1544129
from:750000to:781250=1541918
from:500000to:531250=1551838
from:906250to:937500=1549404
from:625000to:656250=1550692
from:375000to:406250=1544616
from:62500to:93750=1554626
from:875000to:906250=1548556
from:343750to:375000=1554709
from:281250to:312500=1545881
from:125000to:156250=1550330
from:312500to:343750=1548005
from:250000to:281250=1552814
from:31250to:62500=1547229
from:187500to:218750=1545491
from:0to:31250=1547854
没有计算总的sun,因为RecursiveAction是没有返回值的,改为继承RecursiveTask,如下
1 public class ForkJoinPool2 {
2 static int[] nums = new int[1000000];
3 static final int MAX_NUM = 50000;
4 static Random r = new Random();
5 //求和
6 static {
7 for(int i=0; i<nums.length;i++){
8 nums[i]=r.nextInt(100);
9 }
10 System.out.println(Arrays.stream(nums).sum());
11 }
12 static class AddTask extends RecursiveTask<Long> {
13 int start,end;
14 AddTask(int s, int e){
15 start = s;
16 end = e;
17 }
18 protected Long compute(){
19 if(end-start<=MAX_NUM){
20 long sum = 0L;
21 for(int i=start;i<end;i++){
22 sum+=nums[i];
23 }
24 return sum;
25 }
26 int middle = start+(end-start)/2;
27 AddTask subTask1 = new AddTask(start,middle);
28 AddTask subTask2 = new AddTask(middle,end);
29 subTask1.fork();
30 subTask2.fork();
31 return subTask1.join()+subTask2.join();
32 }
33 }
34 public static void main(String[] agrs) throws IOException{
35 ForkJoinPool fjp = new ForkJoinPool();
36 AddTask task = new AddTask(0,nums.length);
37 fjp.execute(task);
38 long result = task.join();
39 System.out.println(result);
40 //System.in.read();
41 }
42 }
2.11 线程池——ThreadPoolExecutor
线程池的底层实现:
发现它们都基于ThreadPoolExector,WorkStealingPool与ForkJoinPool的底层都是ForkJoinPool。
2530
570
2.12——parallelStreamAPI
1 public class T_ParallelStreamAPI {
2 public static void main(String[] agrs){
3 List<Integer> nums = new ArrayList<>();
4 Random r = new Random();
5 for(int i=0;i<10000;i++){
6 nums.add(1000000+r.nextInt(1000000));
7 }
8 long start = System.currentTimeMillis();
9 nums.forEach(v->isPrime(v));
10 long end = System.currentTimeMillis();
11 System.out.println(end-start);
12
13 //使用parallelStream api
14 start = System.currentTimeMillis();
15 //默认使用多线程
16 nums.parallelStream().forEach(T_ParallelStreamAPI::isPrime);
17 end = System.currentTimeMillis();
18 System.out.println(end-start);
19 }
20 static boolean isPrime(int num){
21 for(int i=2;i<num/2;i++){
22 if(num%i==0)
23 return false;
24 }
25 return true;
26 }
27 }
2530
570