jdk8入门,包括lambda、juc

说明:写这篇博客的目的是,为了自己查找方便。

很多内容来自于https://www.bilibili.com/video/av90007319

一、Lambda 表达式

  作用:让代码简化,流水线式的逻辑。可以简化 匿名内部类的 写法。

  首先介绍函数式接口,这个接口只有一个方法。

1.1 简化匿名内部类

@FunctionalInterface
public interface Swimmable {
     void swim();
}
public class LambdaExpressDemo {
    public void goSwimming(Swimmable swimmable) {
        swimmable.swim();
    }
}
LambdaExpressDemo lambdaExpressDemo = new LambdaExpressDemo();
// 这是传统的 匿名内部类的写法
lambdaExpressDemo.goSwimming(new Swimmable() {
    @Override
    public void swim() {
        System.out.println("这是传统的 匿名内部类的写法");
    }
});

lambdaExpressDemo.goSwimming(() -> System.out.println("lambda表达式的写法"));

 

 1.2 简化线程实现的写法

   比如 new runable(){} 用lambda写,就是 ()-> {// TODO 具体的业务} 。

 1.3 集合的常用操作:排序。

  除了使用 lambda表达式来代替 new Comparator(){},还有更简单的写法。这个写法,叫做方法引用。

  给定一个 Person类。

        List<Person> personArrayList = new ArrayList<>();
        personArrayList.add(new Person("Tom", 22, 166));
        personArrayList.add(new Person("Jerry", 76, 176));
        personArrayList.add(new Person("张三", 55, 188));
        personArrayList.add(new Person("李四", 76, 199));
        personArrayList.sort(Comparator.comparingInt(Person::getAge).thenComparing(Person::getName));
        personArrayList.forEach(System.out::println);

 

 运行结果是

Person{ Tom, 22, 166}
Person{ 张三, 55, 188}
Person{ Jerry, 76, 176}
Person{ 李四, 76, 199}

 

1.4 lambda表达式 和 匿名内部类的 比较

  1. 需要实现的类型不一样
    • 匿名内部类 需要抽象类 ,接口 都可以。
    • 而 lambda表达式 必须实现一个 函数式接口。
  2. 可以实现的抽象方法 的 数量不一样编译过程不一样
    • 匿名内部类 可以 实现 多个抽象方法。
    • 而 lambda表达式 只能 实现一个。
  3. 编译过程不一样
    • 匿名内部类 在 编译后 ,会形成一个 XXXXX$1.class文件。
    • 而 lambda表达式 在 程序运行的时候,不会生成 新的class文件。

 1.5 lambda内使用的变量是final类型

 

  lambda内的list是通过值传递的方式,拿到的一个外部变量的一个副本,它们都指向 new ArrayList<>()这个对象。

在lambda的业务处理过程,不允许改变 list变量的内存地址。

1.6 柯理化

  柯理化的特征是,把多个参数的函数 转换为 只有一个参数的 函数。 x -> y -> x + y 这种写法,叫做级联表达式。

 

    public static void main(String[] args) {
        Function<Integer, Function<Integer, Integer>> fun = x -> y -> x + y;
        System.out.println(fun.apply(2).apply(6));
    }

 

二、内置的函数式接口

  1. 供给型函数式接口  Supplier ,提供一个结果输出。

@FunctionalInterface
public interface Supplier<T> {
    T get();
  // 省略其它
}

 2. 有输入 也有 输出的 function

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
  // 省略其它
}

3. 消费型, 要求有输入参数。

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
  // 省略其它
}

4. 判断处理,要求有输入。返回 boolean 值。

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
  // 省略其它 }

 

三、 juc的锁 

3.1 可重入锁 ReentrantLock 。

解释 公平锁和非公平锁的感念,公平锁 有先来后到的顺序,非公平锁则插队执行,不按顺序。非公平锁的效率更高。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Lock 和 synchronized 的区别
 * 1、synchronized 是java的关键字;Lock 是java类。
 * 2、synchronized 自动释放锁,Lock需要手动。
 * 3、synchronized 适合锁少量的代码。Lock适合大量的代码,非常灵活。
 *
 */
@SuppressWarnings("all")
public class SaleTicketDemo02 {
    public static void main(String[] args) {
        Ticket2 ticket = new Ticket2();
        new Thread(() -> { for (int i = 0; i < 60; i++) ticket.sale(); }, "a").start();
        new Thread(() -> { for (int i = 0; i < 60; i++) ticket.sale(); }, "b").start();
    }

}

class Ticket2 {
    private int num = 20;
    Lock lock = new ReentrantLock(false); // 非公平锁, 为了工作效率。

    public void sale() {
        lock.lock();

        try {
            lock.tryLock(5, TimeUnit.SECONDS);
            if (num > 0) {
                System.out.println("还剩下 " + (--num) + " 张票 " + " ++++++ " + Thread.currentThread().getName());
                TimeUnit.MILLISECONDS.sleep(500);
            }else {
                System.exit(1);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

}

 

3.2 传统的生产者和消费者

这里使用的是 wait 和 notify 。也叫做线程间通信 。

package com.kuang.productAndComsumer;

/**
* jdk的官方建议,在while内使用wait() 。 * 留意这个虚假唤醒的问题。 * synchronized (obj) { * while (<condition does not hold>) * obj.wait(); * ... // Perform action appropriate to condition * } */ public class A { public static void main(String[] args) { Data data = new Data(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "a").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "b").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "c").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "d").start(); } } class Data { private int num = 0; public synchronized void increment() throws InterruptedException { while (num != 0) { wait(); } num++; System.out.println(Thread.currentThread().getName() + " => " + num); notify(); } public synchronized void decrement() throws InterruptedException { while (num == 0) { wait(); } num--; System.out.println(Thread.currentThread().getName() + " => " + num); notify(); } }

 

3.3  JUC 版本的 await 和 signal

好处是 做到 精准唤醒。

package com.kuang.productAndComsumer;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 这个是 JUC 版本的 await 和 signal。交替唤醒。
 * 而且 可以做到 精准地唤醒。
 */
public class B {
    public static void main(String[] args) {
        Data2 data = new Data2();
        new Thread(() -> { for (int i = 0; i < 10; i++) data.increment(); }, "a").start();
        new Thread(() -> { for (int i = 0; i < 10; i++) data.decrement(); }, "b").start();
    }
}


class Data2 {
    private int num = 0;
    Lock lock = new ReentrantLock();
    Condition inCondition = lock.newCondition();
    Condition deCondition = lock.newCondition();

    public void increment() {
        lock.lock();
        try {
            while (num != 0) {
                inCondition.await();
            }
            num++;
            System.out.println(Thread.currentThread().getName() + " => " + num);
            deCondition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void decrement() {
        lock.lock();
        try {
            while (num == 0) {
                deCondition.await();
            }
            num--;
            System.out.println(Thread.currentThread().getName() + " => " + num);
            inCondition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
}

 

3.4 8个锁的问题

情况1: a和b两个线程,是共用同一把锁 。 a线程 是 sendMsg, 它先拿到锁,先执行。等它执行完毕后,再执行b线程的 makeCall() 。

import java.util.concurrent.TimeUnit;

public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()-> {
            phone.sendMsg();
        }, "a").start();

        TimeUnit.SECONDS.sleep(3);

        new Thread(()-> {
            phone.makeCall();
        }, "b").start();
    }
}

class Phone {
    public synchronized void sendMsg(){
        System.out.println("发送短信。");
    }

    public synchronized void makeCall(){
        System.out.println("打电话");
    }

}

  

情况2:哪怕 a线程跑得慢,也是它先执行。

import java.util.concurrent.TimeUnit;

public class Test1 {
    public static void main(String[] args){
        Phone phone = new Phone();
        new Thread(()-> {
            phone.sendMsg();
        }, "a").start();

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

        new Thread(()-> {
            phone.makeCall();
        }, "b").start();
    }
}

class Phone {
    public synchronized void sendMsg() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发送短信。");
    }

    public synchronized void makeCall(){
        System.out.println("打电话");
    }

}

 

情况3: 如果和一个普通方法竞争,普通方法会先执行。

import java.util.concurrent.TimeUnit;

public class Test2 {
    public static void main(String[] args){
        Phone2 phone = new Phone2();
        new Thread(()-> {
            phone.sendMsg();
        }, "a").start();

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

        new Thread(()-> {
            phone.hello();
        }, "b").start();
    }
}

class Phone2 {
    public synchronized void sendMsg() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发送短信。");
    }

    public synchronized void makeCall(){
        System.out.println("打电话");
    }

    public void hello(){
        System.out.println("hello");
    }

}

 

情况4: 如果是两把不同的锁,锁之间就不存在竞争了。

import java.util.concurrent.TimeUnit;

public class Test2 {
    public static void main(String[] args){
        Phone2 phone = new Phone2();
        Phone2 phone2 = new Phone2();
        new Thread(()-> {
            phone.sendMsg();
        }, "a").start();

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

        new Thread(()-> {
            phone2.makeCall();
        }, "b").start();
    }
}

class Phone2 {
    public synchronized void sendMsg() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发送短信。");
    }

    public synchronized void makeCall(){
        System.out.println("打电话");
    }

    public void hello(){
        System.out.println("hello");
    }

}

 

结果是:

打电话
发送短信。

 

 情况5: 如果同一把锁,但方法是static,就存在竞争关系。因为,锁的是 这个类class,类一加载,就拿到了这把锁。

import java.util.concurrent.TimeUnit;

public class Test2 {
    public static void main(String[] args){
        Phone2 phone = new Phone2();
//        Phone2 phone2 = new Phone2();
        new Thread(()-> {
            phone.sendMsg();
        }, "a").start();

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

        new Thread(()-> {
            phone.makeCall();
        }, "b").start();
    }
}

class Phone2 {
    public static synchronized void sendMsg() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发送短信。");
    }

    public synchronized void makeCall(){
        System.out.println("打电话");
    }

    public void hello(){
        System.out.println("hello");
    }

}

 

 情况6: 静态方法 加上 两个对象Phone。结果是先 发送短信 。原因还是因为 static, 锁的是 这个class 类,同一把锁

import java.util.concurrent.TimeUnit;

public class Test2 {
    public static void main(String[] args){
        Phone2 phone = new Phone2();
        Phone2 phone2 = new Phone2();
        new Thread(()-> {
            phone.sendMsg();
        }, "a").start();

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

        new Thread(()-> {
            phone2.makeCall();
        }, "b").start();
    }
}

class Phone2 {
    public static synchronized void sendMsg() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发送短信。");
    }

    public static synchronized void makeCall(){
        System.out.println("打电话");
    }

    public void hello(){
        System.out.println("hello");
    }

}

 

 情况7: 如果一个线程调用的是 static, 另一个线程调用的不是 static方法。那就是2把锁。结果是先打电话。

import java.util.concurrent.TimeUnit;

public class Test2 {
    public static void main(String[] args){
        Phone2 phone = new Phone2();
//        Phone2 phone2 = new Phone2();
        new Thread(()-> {
            phone.sendMsg();
        }, "a").start();

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

        new Thread(()-> {
            phone.makeCall();
        }, "b").start();
    }
}

class Phone2 {
    public static synchronized void sendMsg() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发送短信。");
    }

    public synchronized void makeCall(){
        System.out.println("打电话");
    }

    public void hello(){
        System.out.println("hello");
    }

}

 

 情况8: 在情况7的基础上,如果是两个Phone对象调用,结果也是 先打电话。

import java.util.concurrent.TimeUnit;

public class Test2 {
    public static void main(String[] args){
        Phone2 phone = new Phone2();
        Phone2 phone2 = new Phone2();
        new Thread(()-> {
            phone.sendMsg();
        }, "a").start();

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

        new Thread(()-> {
            phone2.makeCall();
        }, "b").start();
    }
}

class Phone2 {
    public static synchronized void sendMsg() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发送短信。");
    }

    public synchronized void makeCall(){
        System.out.println("打电话");
    }

    public void hello(){
        System.out.println("hello");
    }

}

 

4、 并发包下的集合类

 4.1 ArrayList不安全

  Vector使用 syncchronized , 所以效率低。CopyOnWriteArrayList效率更好。和 CopyOnWriteArrayList 类似的有 CopyOnWriteArraySet

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
*
* 1、Vector 是线程安全的。ArrayList 就不是。
* 2、但可以通过 Collections.synchronizedList(new ArrayList<>()) 方法变得线程安全。
* 3、Vector使用 syncchronized , 所以效率低。CopyOnWriteArrayList效率更好。
*
*/
public class ListTest {

public static void main(String[] args) {
// List<String> list = new ArrayList<>();
// List<String> listSync = Collections.synchronizedList(new ArrayList<>());
// Vector<String> vector = new Vector<>();

CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();

for (int i = 0; i < 10; i++) {
new Thread(()-> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
}, i+"").start();
}
}

}
 

 

 引出一个小知识点,HashSet 的本质就是HashMap,官方的源码就是这么写的。

    public HashSet() {
        map = new HashMap<>();
    }

 

4.2  ConcurrentHashMap

ConcurrentHashMap 添加进 null值,会报出异常。而 HashMap 就可以存null值。
    public static void main(String[] args) throws InterruptedException {
        Map<String, String> map = new HashMap<>();
        ConcurrentHashMap<String, String> concurrentHashMap = new ConcurrentHashMap<>();
        for (int i = 0; i < 30; i++) {
            final int temp = i;
            new Thread(() -> concurrentHashMap.put(Thread.currentThread().getName(), temp + ""), i + "").start();
        }
        TimeUnit.SECONDS.sleep(5);

        concurrentHashMap.forEach((k, v) -> System.out.println(k + " : " + v));
        map.put(null, null);
        System.out.println(map);
        concurrentHashMap.put(null, null);
        System.out.println(concurrentHashMap);
    }

 

 

五、Callable简单使用

  特点是:有返回值,可以抛出异常。Callable 需要 FutureTask<> 做适配。

public class CallableTest {
    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        FutureTask futureTask = new FutureTask<>(new MyThread());
        new Thread(futureTask, "a").start();
        String res = (String) futureTask.get(2, TimeUnit.SECONDS);  // 等待2秒,没有返回值,就算了,不等了。
        System.out.println(res);
    }
}

class MyThread implements Callable<String> {
    @Override
    public String call() {
        return UUID.randomUUID().toString();
    }
}

 

六、juc并发

6.1 常用的辅助类

  6.1.1 CountDownLatch 类似倒计时的功能

    /**
     * 使用场景: 有前提任务要先做
     */
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        for (int i = 1; i <= 4; i++) {
            new Thread(() -> {
                System.out.println("Thread name: " + Thread.currentThread().getName());
                countDownLatch.countDown();
            }, i + "").start();
        }
        countDownLatch.await(); // 这里的 await 是必须要有的
        System.out.println("Thread name: " + Thread.currentThread().getName() + " 倒计时结束");
    }

  6.1.2 还有 类似累加器CyclicBarrier 的使用

  它的作用和 CountDownLatch 非常类似。都有任务先后执行的功能。

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(4, ()-> System.out.println("加法器累加结束,接下来执行新的任务。"));
        for (int i = 1; i <= 6; i++) {
            final int temp = i;
            new Thread(()-> {
                System.out.println(temp);
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

  6.1.3 信号量Semaphore

  起到 并发限流的作用。

        // 线程数 10 并发
        Semaphore semaphore = new Semaphore(10);
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"进来");
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println(Thread.currentThread().getName()+"出去");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();
                }
            }).start();
        }
    }

6.2 读写锁

  源码接口

public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     *
     * @return the lock used for reading
     */
    Lock readLock();

    /**
     * Returns the lock used for writing.
     *
     * @return the lock used for writing
     */
    Lock writeLock();
}

 

  写锁是独占的,只允许一个线程写。读锁是线程共享的,多个线程一起读。

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadAndWrite {
    public static void main(String[] args) {
        MyCache myCache = new MyCache();
        ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        for (int i = 1; i <= 10; i++) {
            final int temp = i;
            new Thread(() -> {
                readWriteLock.writeLock().lock();
                try {
                    myCache.put(temp + "", temp + "");
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    readWriteLock.writeLock().unlock();
                }

            }).start();
        }

        for (int i = 1; i <= 10; i++) {
            final int temp = i;
            new Thread(() -> {
                readWriteLock.readLock().lock();
                myCache.get(temp + "");
                readWriteLock.readLock().unlock();
            }).start();
        }
    }
}

class MyCache {
    volatile Map<String, Object> map = new HashMap<>();

    void get(String key) {
        System.out.println(Thread.currentThread().getName() + "开始读");
        map.get(key);
        System.out.println(Thread.currentThread().getName() + "读完毕");
    }

    void put(String key, Object value) {
        System.out.println(Thread.currentThread().getName() + "开始写");
        map.put(key, value);
        System.out.println(Thread.currentThread().getName() + "写完毕");
    }
}

6.3 阻塞队列

  会抛出异常 不会抛出异常 阻塞等待 超时等待
添加 add() offer(e) put(e) offer(e,t,u)
移除 remove() poll() take() poll(t,u)
队首元素 element() peek() - -

public static void test1() { ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3); blockingQueue.add("a"); blockingQueue.add("b"); blockingQueue.add("c"); // blockingQueue.add("a"); System.out.println(blockingQueue.element()); blockingQueue.remove(); blockingQueue.remove(); System.out.println(blockingQueue.element()); blockingQueue.remove(); System.out.println(blockingQueue.element()); // blockingQueue.remove(); }
    public static void test2() {
        ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.offer(1));
        System.out.println(blockingQueue.offer(2));
        System.out.println(blockingQueue.offer(3));

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.peek());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.peek());
    }
    public static void test3() throws InterruptedException {
        ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);
        blockingQueue.put(1);
        blockingQueue.put(2);
        blockingQueue.put(3);
//        blockingQueue.put(1);
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
    }
    public static void test4() throws InterruptedException {
        ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);
        blockingQueue.offer(1);
        blockingQueue.offer(1);
        blockingQueue.offer(1);
        blockingQueue.offer(1, 500, TimeUnit.MILLISECONDS);

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll(5, TimeUnit.SECONDS));
    }

6.4 同步队列 SynchronousQueue

   这个队列只存一个元素。它的使用方法和阻塞队列很相似,区别就是容量。

 

6.5 线程池

  6.5.1 使用 Executors 来创建线程池。

    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);   // 最多5个线程并发
//        ExecutorService threadPool = Executors.newCachedThreadPool();     // 根据电脑的cpu线程数而定,遇强则强。
        try {
            for (int i = 0; i < 20; i++) {
                threadPool.execute(()-> System.out.println(Thread.currentThread().getName()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }

  除了上面两个方法外, 还有 Executors.newSingleThreadExecutor() , 创建单线程。

6.5.2 线程池的7个参数

    public ThreadPoolExecutor(int corePoolSize,  核心线程池数
                              int maximumPoolSize,  最大线程池数
                              long keepAliveTime,  存活时间
                              TimeUnit unit,  时间单位
                              BlockingQueue<Runnable> workQueue,  阻塞队列
                              ThreadFactory threadFactory,  创建线程的工程,默认即可。
                              RejectedExecutionHandler handler)  拒绝策略

    /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

 

   提出线程吧资源耗尽的问题。 Integer.MAX_VALUE, 是 231-1=2147483647 ,21亿多。应该避免使用这个方法。

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

 

  建议使用  ThreadPoolExecutor 来创建线程。

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5, 
                20, 
                5, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(5),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );

 

拒绝策略有默认的方法。拒绝的意思是,最大线程满了,阻塞队列也满了, 就做拒绝。

    /**
     * The default rejected execution handler
     */
    private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();

 有四个拒绝策略。ctrl+h打开。

 

 6.5.3 关于最大线程数怎么确定

  1. IO密集型,比如频繁文件io磁盘落地和读取。
  2. cpu密集型,比如大量统计,累加,计算分析的任务。

 如果电脑是2核4线程,通常核心线程数=2,最大线程数=4。如果IO密集型,最大线程数=8。

Runtime.getRuntime().availableProcessors()  // 获得电脑的线程数

 

 

 

七、流 stream

  根据一个例子来初始stream的魅力。通常的业务都会包括,给数据做筛选,排序,统计等等的操作。

    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();
        list.add(new Person(1, "Tom", 23));
        list.add(new Person(2, "Tomson", 32));
        list.add(new Person(3, "Jack", 12));
        list.add(new Person(4, "Jerry", 56));
        list.add(new Person(5, "Betty", 48));
        list.add(new Person(6, "James", 22));
        
        System.out.println("筛选");
        List<Person> list1 = list.stream()
                .filter(person -> person.getId() % 2 == 0)
                .filter(person -> person.getAge() > 22)
                .sorted(Comparator.comparing(Person::getName).reversed())   // 按照name逆序
                .collect(Collectors.toList());
        list1.forEach(person -> System.out.println(person));

        System.out.println("转小写字母");
        list1.stream()
                .map(person -> {
                    person.setName(person.getName().toLowerCase());
                    return person;
                })
                .forEach(System.out::println);

    }

7.1 针对数值类型 IntStream

int[] arr = new int[]{2, 1, 34, 7, 99};
System.out.println(IntStream.of(arr).sum());

7.2 中间操作和终止操作

  • 比如 map , filter 就是典型的 中间操作, 返回的仍是 stream 。
  • collect,foreach就是终止操作,产生了结果,哪怕打印,也是个结果。
  • 如果一串流处理,最后没有 终止操作,这些中间操作是惰性求值,实际上跟没做一样。

7.3 创建流

 

 

 

 举例

Stream.generate(() -> {return new Random().nextInt(100)+50;})
        .limit(10).forEach(System.out::println);
        ArrayList<Integer> arrayList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            arrayList.add(i);
        }
        arrayList.stream().filter(num -> num % 2 == 0)
                .sorted((i,j) -> i-j).sorted(Comparator.reverseOrder())
                .forEach(System.out::println);

7.4 中间操作

 

无状态操作,对于操作顺序没要求。有转态,就要等之前的操作做完,再做。 

7.5 终止操作

 

 短路操作,对于 无限流是非常有必要的。

7.6 并行流, 使用多线程 提供效率。

stream().parallel()

 

posted on 2020-03-10 17:18  wuyicode  阅读(460)  评论(0编辑  收藏  举报