lambda表达式
sort
public class ComparatorTest {
public static void main(String[] args) {
Apple a1 = new Apple("red",120.33);
Apple a2 = new Apple("red",129.33);
Apple a3 = new Apple("red",119.33);
List<Apple> appleList = Arrays.asList(a1,a2,a3);
test1(appleList);
}
/**
* 方式1 创建类并实现Comparator
*/
public static void test1(List<Apple> appleList){
appleList.sort(new AppleComparator());
System.out.println(JSON.toJSONString(appleList));
}
/**
* 方式2 匿名内部类
*/
public static void test2(List<Apple> appleList){
appleList.sort(new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return o1.getWeight().compareTo(o2.getWeight());
}
});
}
/**
* 方式3 使用Lambda表达式
*/
public static void test3(List<Apple> appleList){
appleList.sort(((o1, o2) -> o1.getWeight().compareTo(o2.getWeight())));
System.out.println(JSON.toJSONString(appleList));
}
/**
* 方式4 方法3改进
*/
public static void test4(List<Apple> appleList){
//comparing中的参数是Function的实现
//其中返回的参数是用于排序的key
appleList.sort(Comparator.comparing((a -> a.getWeight())));
System.out.println(JSON.toJSONString(appleList));
}
/**
* 方式5 使用方法引用
*/
public static void test5(List<Apple> appleList){
appleList.sort(Comparator.comparing((Apple::getWeight)));
System.out.println(JSON.toJSONString(appleList));
}
}
自定义lambda表达式实现接口
定义一个只有一个抽象方法的接口,其实际上是一个函数式接口,可在接口前面加上@FunctionalInterface注解进行验证。
public class LambdaTestB {
public static void main(String[] args) {
Fu2 fu = a->a*5;
System.out.println(fu.add(100));
}
}
@FunctionalInterface
interface Fu2{
int add(int a);
}
注意其lambda表达式的格式应该和add()一致的函数类型
内置的函数式接口
Consumer:消费型接口(void accept(T t))。有参数,无返回值 (上文forEach的参数类型就是Consumer)
Supplier:供给型接口(T get())。只有返回值,没有入参
Function<T, R>:函数型接口(R apply(T t))。一个输入参数,一个输出参数,两种类型不可不同、可以一致
Predicate:断言型接口(boolean test(T t))。输入一个参数,输出一个boolean类型得返回值
线程池
//这个属性是用来存放 当前运行的worker数量以及线程池状态的
//int是32位的,这里把int的高3位拿来充当线程池状态的标志位,后29位拿来充当当前运行worker的数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//存放任务的阻塞队列
private final BlockingQueue<Runnable> workQueue;
//worker的集合,用set来存放
private final HashSet<Worker> workers = new HashSet<Worker>();
//历史达到的worker数最大值
private int largestPoolSize;
//当队列满了并且worker的数量达到maxSize的时候,执行具体的拒绝策略
private volatile RejectedExecutionHandler handler;
//超出coreSize的worker的生存时间
private volatile long keepAliveTime;
//常驻worker的数量
private volatile int corePoolSize;
//最大worker的数量,一般当workQueue满了才会用到这个参数
private volatile int maximumPoolSize;
处理流程
1.查看核心线程池是否已满,不满就创建一条线程执行任务,否则执行第二步。
2.查看任务队列是否已满(Blocking queue),不满就将任务存储在任务队列中,否则执行第三步。
3.查看线程池是否已满,即就是是否达到最大线程池数,不满就创建一条线程执行任务,否则就按照策略处理无法执行的任务。
线程状态切换
运行态->等待态(WAITING)
-
Object.join():把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行
比如线程B中调用了线程A的join()方法,线程A执行完成后,线程B才会开始执行 -
Object.wait():线程进入等待状态,进入等待状态的线程需要依赖其他线程的通知(notify/notifyAll)才能够返回到运行状态
-
LockSupport.park():park函数是将当前调用Thread阻塞,而unpark函数则是将指定线程Thread唤醒。与Object类的wait/notify机制相比,
-
park/unpark有两个优点:
① 以thread为操作对象更符合阻塞线程的直观定义
② 操作更精准,可以准确地唤醒某一个线程(notify随机唤醒一个线程,notifyAll唤醒所有等待的线程),增加了灵活性。
-
park是等待一个许可,unpark是为某线程提供一个许可。
如果某线程A调用park,那么除非另外一个线程调用unpark(A)给A一个许可,否则线程A将阻塞在park操作上 -
unpark操作可以在park操作之前
-
“许可”是不能叠加的,“许可”是一次性的:线程B连续调用了三次unpark函数,当线程A调用park函数就使用掉这个“许可”,如果线程A再次调用park,则进入等待状态
-
等待态->运行态
- Object.notify()
- Object.notifyAll()
- LockSupport.unpark(Thread)
运行态->超时等待(TIMED_WAITING)
超时等待状态在等待状态的基础上增加了超时限制,当达到超时时间后会返回运行状态
-
Thread.sleep(long) 这里单位是millisconds,为了便于控制sleep的时间,可以使用
-
TimeUnit.SECONDS.sleep(long):TimeUnit是java.util.concurrent包下面的一个类,表示给定单元粒度的时间段,作用包括:
-
时间颗粒度转换
//结果:24 System.out.println( TimeUnit.DAYS.toHours( 1 ) ); //结果:3600 System.out.println( TimeUnit.HOURS.toSeconds( 1 )); //结果是:72 System.out.println( TimeUnit.HOURS.convert( 3 , TimeUnit.DAYS ) );
-
延时
TimeUnit.SECONDS.sleep(long);
-
-
Object.wait(long)
-
Thread.join(long)
-
LockSupport.parkNanos(long) LockSupport.parkUntil(long)
超时等待(TIMED_WAITING)->运行态
-
Object.notify()
-
Object.notifyAll()
-
LockSupport.unpark(Thread)
运行态->阻塞态
- 等待进入synchronized方法
- 等待进入synchronized块
阻塞态->运行态
- 获取到锁
安全地终止线程
- 使用interrupt() 中断操作来终止线程
- 通过标示位判断来终止
线程间通信
volatile
用于修饰成员变量,告知程序任何对该变量的访问均需要从共享内存中获取,并且对于它的改变必须同步刷新回共享内存,能保证所有线程对变量访问的可见性。
过多地使用会降低程序执行的效率
synchronized
用于修饰方法或者以同步块的形式来进行使用。确保多个线程在同一时刻,只能有一个线程处于方法或者同步块中,保证了线程对变量访问的可见性和排他性。
任意线程对Object的访问,首先要获取Object的监视器。如果获取失败,线程进入同步队列,状态变为Blocked,当访问Object的前驱(获得了锁的线程)释放了锁,那么该释放操作会唤醒阻塞在同步队列中的线程,使其重新尝试对监视器的获取。
等待/通知机制
- 使用wait()、notify()、notifyAll()的时候需要先对调用对象加锁
- 调用wait()方法后线程进入等待状态,并且释放锁
- 其他线程调用notify()、notifyAll()之后,还需要等调用这两个方法的线程释放锁,等待线程获得了调用对象的锁之后,才会从wait()返回