多线程面试题


参考资料: 马士兵多线程讲解

synchronized

  1. 锁定的是什么?
    对象的锁只有一个,线程1拿到,其他线程就无法操作这个对象。进入阻塞状态,直到synchronized(){}执行结束

  2. .synchronized(this)、synchronized(.class)、synchronized(任意对象)区别
    synchronized (this)代码块是锁定当前对象,所得是用一个对象
    synchronized(任意自定义对象)进行同步操作,对象监视器必须是同一个对象。否则将进行异步操作
    synchronized(
    .class)是对该类的所有实例化对象的所有属性和方法加锁,强制同步。当线程1访问实例化的同步代码,除了线程1,其他线程进入阻塞状态

  3. 类锁()与对象锁

    实现方式
    类锁的实现方式:
    被static和synchronized修饰的方法
    synchronized(*.class)
    对象锁的实现方式:
    被synchronized修饰的方法
    synchronized(this)

    范围
    类锁的范围是整个实体类
    对象锁的范围是当前对象

  4. 同步方法和异步方法是否可以同时调用?
    可以,同步方法需哟拿到对象的锁,异步方法不需要拿到对象的锁,互不影响

  5. 一个同步方法可以调用另一个同步方法么?
    同一个对象锁可以,不同对象的锁就不行

  6. 子类的同步方法是否可以调用父类的同步方法?
    可以,synchronized是可重入锁

  7. synchronized保证了原子性和可见性,因此,效率低

  8. 被synchronized锁定的代码块如果在执行的过程中出现异常,没有使用try-catch捕获会立即中程序,释放对象锁

  9. 不要以字符常量作为锁定对象,否则会出现死锁阻塞

  10. 使用synchronized的代码块越少越好,执行效率越高

  11. 锁的信息记录在堆内存的对象中

  12. synchronized是重量级锁、互斥锁、可重入锁、不公平锁

wait,notify与notifyAll

  1. wait使当前线程阻塞,前提是线程必须获得锁,所以一般配合synchronized使用。
  2. 线程执行wait的时候,会释放当前的锁,然后让出cpu,进入等待状态。
  3. wait方法需要被try catch包含。
  4. notify,唤醒一个阻塞的线程,由jvm调度
  5. notify无法指定某个阻塞的线程
  6. notify,其唤醒的线程,拿到对象锁才可以执行
  7. notifyAll,唤醒所有阻塞的线程
  8. wait、notify与notifyAll都是object的方法
  9. wait, notify, notifyAll一定要在共享对象同步方法或同步代码块中执行,否则会在运行时抛出IllegalMonitorStateException的异常。因为wait, notify, notifyAll包含了对共享对象锁的操作,所以之前一定要先synchronized获取对象锁。
  10. 唤醒线程执行完共享对象的notify或notifyAll方法后,仍然要执行完synchronized修饰的同步代码块中后面的代码才能释放对象锁,因此,通常notify后面尽量减少执行代码,让对象锁尽快释放。
  11. 永远在循环(loop)里调用 wait 和 notify, notifyAll,不是在 If 语句,避免死锁情况发生。

volatile

  1. 保证了可见性,没有保证原子性
  2. volatile会检测主内存的值发生改变,会同时通知使用值的线程重新从栈内存获取值
  3. volatile 并不能保证多个线程共同修改running变量时所带来的不一致问题

AtomXXX类

  1. 此方法可以替代操作数据,++,–操作
  2. 此方法是原子性的,但不能保证多个方法连续调用是原子性的
  3. 代码示例:
class T {
    AtomicInteger count=new AtomicInteger(0);
    /*synchronized*/ void m(){
        for (int i = 0; i < 10000000; i++) {
            /*if (count.get()<1000000)*/
            count.incrementAndGet();    //替代count++的
        }
    }

    public static void main(String[] args) {
        T t=new T();

        List<Thread> threads=new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            threads.add(new Thread(t::m,"thread-"+i));
        }

        threads.forEach((o)->o.start());

        threads.forEach((o)->{
            try {
                o.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        System.out.println(t.count);
    }
}

运行结果:

100000000

Process finished with exit code 0

Countdownlatch

  1. CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行。
  2. CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下
  3. CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已完成任务,然后在闭锁上等待的线程就可以恢复执行任务。
  4. await() 此方法将会使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
  5. countDown() 此方法将递减锁存器的计数,如果计数到达零,则释放所有等待的线程
  6. 使用示例:
public class MyContainer5 {
    //添加volatile,使t2能够得到通知
    volatile List lists=new ArrayList();

    public void add(Object o){
        lists.add(o);
    }

    public int size(){
        return lists.size();
    }

    public static void main(String[] args) {

        MyContainer5 c=new MyContainer5();

        CountDownLatch latch=new CountDownLatch(1);

        new Thread(()->{
            System.out.println("t2启动");
            if (c.size()!=5){
                try {
                    latch.await();

                    //也可以指定等待时间
                    //latch.await(5000,TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("t2结束");

        },"t2").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        new Thread(()->{
            System.out.println("t1启动");
            for (int i = 0; i < 10; i++) {
                c.add(new Object());
                System.out.println("add "+i);

                if (c.size()==5){
                    //打开门闩,让t2得以执行
                    latch.countDown();
                }

                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("t1结束");

        },"t1").start();


    }
}

运行结果
在这里插入图片描述

reentrantlock

  1. lock的子类,如果遇到异常,需要使用try-catch-finally语句捕获异常
  2. finally中需要手动释放锁unlock()
  3. 可重入锁
  4. 特殊的方法
    trylock(),尝试获取锁且可以指定等待时间,获取不到锁可以选择停止
    Iockinterruptibly()和interrupt可以打断线程的长时间等待
    例子:
    线程1线程永远等待,线程2一直等待锁的释放,发现等不到所的释放,t2使用interrupt呼叫别等了,线程1的lockInterruptibly做出响应,就抛出异常停止
    代码:
public static void main(String[] args) {
    Lock lock=new ReentrantLock();

    Thread t1=new Thread(()->{
        lock.lock();
        try {
            System.out.println("t1 start");
            TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
            System.out.println("t1 end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    });

    t1.start();

    Thread t2=new Thread(()->{

        try {
            lock.lockInterruptibly(); //可以对interrupt()做出响应
            System.out.println("t2 start");
            TimeUnit.SECONDS.sleep(5);
            System.out.println("t2 end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    });

    t2.start();

    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    t2.interrupt();//打断线程2的等待
}

结果:

t1 start
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
	at yxxy.c_020.ReentrantLock4.lambda$main$10(ReentrantLock4.java:33)
	at yxxy.c_020.ReentrantLock4$$Lambda$2/258952499.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
	at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
	at yxxy.c_020.ReentrantLock4.lambda$main$10(ReentrantLock4.java:40)
	at yxxy.c_020.ReentrantLock4$$Lambda$2/258952499.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)

  1. 可以指定公平锁在创建线程的时候指定
ReentrantLock lock=new ReentrantLock(true);//参数为true表示为公平锁

高并发容器

容器

  1. ConcurrentHashMap
    1.5加入,效率最高且是同步的

  2. ConcurrentSkipListMap
    1.6加入,高并发且排序

  3. CopyOnWriteArrayList
    1.5加入,写时复制容器 写时效率低,读时效率高 适合写少读多的环境
    事件监听器

  4. 使集合同步的一个方法,使用Collection.SynchronizedXXX,1.2加入
    代码示例:

public class T01_ConcurrentMap {
    public static void main(String[] args) {
        Map<String,String> map= new ConcurrentHashMap<>();
//        Map<String,String> map= new ConcurrentSkipListMap<>();    //高并发并且排序

//        Map<String,String> map= new Hashtable<>();
//        Map<String,String> map= new HashMap<>();
        //TreeMap
        Random r=new Random();
        Thread[] ths=new Thread[100];
        CountDownLatch latch=new CountDownLatch(ths.length);
        long start=System.currentTimeMillis();
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new Thread(()->{
                for (int j = 0; j < 10000; j++) {
                    map.put("a"+r.nextInt(100000),"a"+r.nextInt(100000));
                    latch.countDown();
                }
            });
        }

        Arrays.asList(ths).forEach(t->t.start());

        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long end=System.currentTimeMillis();
        System.out.println(end-start);
    }
}

运行结果:

分别测试:
ConcurrentHashMap
48
ConcurrentSkipListMap
314
HashTable 同步
58
HashMap  不同步
86

高并发队列

  1. LinkedBlockingQueue
    1.5加入,此队列是无界队列,且是阻塞队列,一旦容器空了,就会让消费者线程等待,唤醒生产者线程
  2. ArrayBlockingQueue
    1.5加入,容器数量满了,继续添加
    add会报Queue full 异常
    offer不会报异常,此方法的返回值是boolean,告诉你你的添加是否成功true成功,false失败,后面加入参数表示等待一秒后添加
    put满了就会等待,线程阻塞
  3. DelayQueue
    延时队列,1.5加入
    适合使用实时执行任务的场景
    使用需要注意:
    重写以下两个方法:
    CompareTo(Delayed o):Delayed接口继承了Comparable接口,因此有了这个方法。
    getDelay(TimeUnit unit):这个方法返回到激活日期的剩余时间,时间单位由单位参数指定。
  4. LinkedTransferQueue
    1.7加入,特殊方法:
    transfer
    用于消费者多线程先启动,生产者启动,先去查看有没有消费者线程,有的话,直接传给消费 者线程,同时此生产者线程阻塞,知道消费者使用take从队列读取消息
    take
    从队列中获取消息
    TransferQueue用于更高的并发情况,可用于实时消息处理
    容量是有数量的
  5. SynchronousQueue
    1.5加入,一种特殊的TransferQueue容器,阻塞队列
    容量为0
    代码示例:
public class T09_SynchronusQueue {  //容量为0
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> strs=new SynchronousQueue<>();

        new Thread(()->{
            try {
                System.out.println(strs.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        strs.put("aaa");  //阻塞等待消费者消费
        //strs.add("aaa");
        System.out.println(strs.size());
    }
}
使用add添加数据
Exception in thread "main" java.lang.IllegalStateException: Queue full
	at java.util.AbstractQueue.add(AbstractQueue.java:98)
	at yxxy.c_025.T09_SynchronusQueue.main(T09_SynchronusQueue.java:20)

使用putt添加数据

0
aaa

Process finished with exit code 0

put的实现调用了transfer,设计的初衷是为了做实时任务,生产者的使用之前,必须看到消费者线程唤醒或出现

线程池

线程池的最顶级接口是
Executor
只有一个方法void execute(Runnable command)
执行线程,没有返回值

ExecutorService
继承了Executor接口,里面定义了线程池的一些常用方法
**isShutdown(),submit(),isTerimated()**等等

callable
类似于Runnable,是一个任务队列,队列开始,执行call(),只不过call()方法有返回值,也可以抛出异常
Runnable的run()方法是重写的,没有返回值,不能抛出异常

Executors
execuotr,executorservice,scheduleExecutorService,ThreadFactory,Callable类提供方法实现的一个工厂类
ThreadPool
线程池:一个池子,用来存放线程,提高了线程的重复使用率,提高了响应速度。不用频繁打开线程,过度消耗cpu资源

FixedThreadPool

创建固定数量的线程池
若等待的线程超过线程池的数量,则固定数量的线程池会将等待的线程放到此放到任务队列中,等线程池执行完成,就将等待的任务队列放入线程池中

 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

源码,是将值传给ThreadPoolExecutot,将个数的值传给ThreadPoolExecutor构造方法实例化

代码示例:

public class T05_ThreadPool {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService service= Executors.newFixedThreadPool(5);   //execute submit
        for (int i = 0; i < 6; i++) {
            service.execute(()->{
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            });
        }

        System.out.println(service);

        service.shutdown();
        System.out.println(service.isTerminated());
        System.out.println(service.isShutdown());
        System.out.println(service);

        TimeUnit.SECONDS.sleep(5);
        System.out.println(service.isTerminated());
        System.out.println(service.isShutdown());
        System.out.println(service);


    }
}

方法解读:
Shutdown()
正常关闭,所有线程执行完,才会关闭
shutdownnow()
立即关闭线程池,不等待线程池执行线程完成
isTerminated()
线程池的所有线程是否执行完
isShutdown()
是否关闭
运行结果:

java.util.concurrent.ThreadPoolExecutor@85ede7b[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
false
true
java.util.concurrent.ThreadPoolExecutor@85ede7b[Shutting down, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
pool-1-thread-4
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-5
pool-1-thread-4
true
true
java.util.concurrent.ThreadPoolExecutor@85ede7b[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]

CacheThreadPool

缓存线程池
当一个线程需要过来请求时,缓存线程池开启一个新的线程,开始执行线程,若此时又来一个线程请求,缓存线程池会查看池中是否有可用线程,有的话,就使用开启过的线程,没有的话,在开启一个线程执行新请求的线程
空闲时间超过60s,会将线程示例自动销毁,减少内存消耗

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

源码,设置数量为0-int类型的最大值,ThreadPoolExecutor构造方法实例化
将此参数传给但是创建数量与设备有关

代码示例:

public class T08_CachedPool {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService service= Executors.newCachedThreadPool();
        System.out.println(service);

        for (int i = 0; i < 2; i++) {
            service.execute(()->{
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            });
        }

        System.out.println(service);

        TimeUnit.SECONDS.sleep(80);

        System.out.println(service);
    }
}

运行结果:

java.util.concurrent.ThreadPoolExecutor@677327b6[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@677327b6[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@677327b6[Running, pool size = 2, active threads = 0, queued tasks = 0, completed tasks = 2]

Process finished with exit code 1

SIngleThreadPool

单个线程池
只有1个数量的线程池
当被线程占用时,其他的任务需要进入队列等待
只有一个线程 保证线程按顺序执行

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

源码,线程池数量设置为1,ThreadPoolExecutor构造方法实例化

代码示例:

public class T09_SingleThreadPool {
    public static void main(String[] args) {
        ExecutorService service= Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            final int j=i;
            service.execute(()->{
                System.out.println(j+" "+Thread.currentThread().getName());
            });
        }
    }
}

运行结果:

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

Process finished with exit code 1

SchedulePool

定时器线程池/延时线程池

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

最终,也是调用ThreadPoolExecutor
newScheduledThreadPool(int corePoolSize)
corepoolsize为定时器线程池/延时线程池的数量

代码示例:

public class T10_SchedulePool {
    public static void main(String[] args) {
        ScheduledExecutorService service= Executors.newScheduledThreadPool(4);
        service.scheduleAtFixedRate(()->{
            try {
                TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
        },0,500,TimeUnit.MILLISECONDS);
    }
}

运行结果:

pool-1-thread-1
pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4

Process finished with exit code 1

WorkStealingThreadPool

工作窃取
主动找活干,自己的线程池的线程执行完成,会去找其他线程池里未完成的线程,执行该线程
会看cpu几核,会启动多少默认的线程
精灵线程daemon线程,mian线程不阻塞的话,看不到输出 jvm不停止,这个线程就一直运行

public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

代码示例:

public class T11_WorkStealingPool {
    public static void main(String[] args) throws IOException {
        ExecutorService service= Executors.newWorkStealingPool();

        System.out.println(Runtime.getRuntime().availableProcessors());

        service.execute(new R(1000));
        service.execute(new R(2000));
        service.execute(new R(2000));
        service.execute(new R(2000));
        service.execute(new R(2000));

        //由于产生的精灵线程(守护线程、后台线程),主线程不阻塞的话,看不到输出
        System.in.read();
    }

    static class R implements Runnable{

        int time;

        R(int t){
            this.time=t;
        }

        @Override
        public void run() {
            try {
                TimeUnit.MILLISECONDS.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(time+" "+Thread.currentThread().getName());
        }
    }
}

运行结果:

4
1000 ForkJoinPool-1-worker-1
2000 ForkJoinPool-1-worker-3
2000 ForkJoinPool-1-worker-2
2000 ForkJoinPool-1-worker-0
2000 ForkJoinPool-1-worker-1

Process finished with exit code 1

可以看出,前四行中第一个在1秒钟线程完成,其他三个cpu都是2秒,此时cpu1处于空闲,去找到空闲的线程执行,所以最后一行还是cpu1

ForkJoinThreadPool

分叉合并
源码不是通过ThreadPoolExecutor类实现的,是一个独立的类,是通过AbstractExecutorService来实现的
如果有一个特别大的任务,回切分成小的子任务,可以指定子任务的大小,分完之后,将结果加到一起 ,大数据处理使用
使用需要继承RecursiveAction和RecursiveTask 区别
RecursiveAction没有返回值,需要手动打印
RecursiveTask 有返回值

public ForkJoinPool() {
        this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
             defaultForkJoinWorkerThreadFactory, null, false);
    }

代码示例:

public class T12_ForkJoinPool {
    static int[] nums = new int[1000000];
    static final int MAX_NUM = 50000;
    static Random r = new Random();

    static {
        for (int i = 0; i < nums.length; i++) {
            nums[i] = r.nextInt(100);
        }
        System.out.println(Arrays.stream(nums).sum());
    }

    /*static class AddTask extends RecursiveAction{

        int start,end;

        AddTask(int s,int e){
            this.start=s;
            this.end=e;
        }

        @Override
        protected void compute() {
            if (end-start<=MAX_NUM){
                long sum=0L;
                for (int i = start; i < end; i++) {
                    sum+=nums[i];
                }
                System.out.println("from:"+start+" to:"+end+" = "+sum);
            }else{
                int middle=start+(end-start)/2;

                AddTask subTask1=new AddTask(start,middle);
                AddTask subTask2=new AddTask(middle,end);

                subTask1.fork();
                subTask2.fork();
            }
        }
    }*/

    static class AddTask extends RecursiveTask<Long> {

        int start, end;

        AddTask(int s, int e) {
            this.start = s;
            this.end = e;
        }

        @Override
        protected Long compute() {
            if (end - start <= MAX_NUM) {
                long sum = 0L;
                for (int i = start; i < end; i++) {
                    sum += nums[i];
                }
                return sum;
            }

            int middle = start + (end - start) / 2;

            AddTask subTask1 = new AddTask(start, middle);
            AddTask subTask2 = new AddTask(middle, end);

            subTask1.fork();
            subTask2.fork();

            return subTask1.join() + subTask2.join();

        }
    }

    public static void main(String[] args) throws IOException {
        ForkJoinPool fjp = new ForkJoinPool();
        AddTask task = new AddTask(0, nums.length);
        fjp.execute(task);
        long result = task.join();
        System.out.println(result);

        //System.in.read();
    }

}

两种运行结果:
RecursiveAction

49472075
from:468750 to:500000 = 1552625
from:968750 to:1000000 = 1551344
from:437500 to:468750 = 1535352
from:937500 to:968750 = 1542129
from:406250 to:437500 = 1544944
from:906250 to:937500 = 1553500
from:375000 to:406250 = 1540861
from:875000 to:906250 = 1547955
from:343750 to:375000 = 1541029
from:843750 to:875000 = 1539541
from:312500 to:343750 = 1540001
from:281250 to:312500 = 1547936
from:250000 to:281250 = 1544375
from:812500 to:843750 = 1548957
from:218750 to:250000 = 1547361
from:187500 to:218750 = 1549289
from:781250 to:812500 = 1554749
from:156250 to:187500 = 1544155
from:750000 to:781250 = 1556202
from:125000 to:156250 = 1540425
from:718750 to:750000 = 1543888
from:93750 to:125000 = 1545415
from:62500 to:93750 = 1553452
from:687500 to:718750 = 1540641
from:656250 to:687500 = 1553069
from:31250 to:62500 = 1549308
from:0 to:31250 = 1551091
from:593750 to:625000 = 1548623
from:562500 to:593750 = 1549207
from:531250 to:562500 = 1546033
from:500000 to:531250 = 1529665
from:625000 to:656250 = 1538953

RecursiveTask

49516750
49516750

Process finished with exit code 0

ThreadPoolExecutor

此类除了ForkPoolExecutor,以上的其他线程池都是由ThreadPoolExecutor实现的

parallelStream

多线程,必然讲到效率的问题
1.8的parallelStream对于数据的处理能力很高,多线程编写的
比较效率时间
代码示例:

public class T14_ParallelStreamApi {

    public static void main(String[] args) {
        List<Integer> nums=new ArrayList<>();
        Random r=new Random();
        for (int i = 0; i < 10000; i++) {
            nums.add(1000000+r.nextInt(1000000));
        }

        //System.out.println(nums);

        long start=System.currentTimeMillis();
        nums.forEach(v->isPrime(v));
        long end=System.currentTimeMillis();
        System.out.println(end-start);

        //使用parallel stream api

        start=System.currentTimeMillis();
        nums.parallelStream().forEach(T14_ParallelStreamApi::isPrime);
        end=System.currentTimeMillis();

        System.out.println(end-start);
    }

    private static boolean isPrime(Integer num) {
        for (int i = 2; i < num/2; i++) {
            if (num % i == 0){
                return false;
            }
        }
        return true;
    }
}

运行结果:

2762
1095

Process finished with exit code 0

可以看出ParalleStream的效率比平常方式高出一半

本文章将持续更新,欢迎互相学习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值