14、四大函数式接口
(1)函数式接口
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
package com.gykj;
import java.util.function.Function;
/**
* Function 函数式接口,有一个数日参数,有一个输出
* 只要是 函数式解耦,可以用lamnda表达式简化
*/
public class FunctionDemo {
public static void main(String[] args) {
Function function=new Function<String,String>(){
@Override
public String apply(String s) {
return s;
}
};
Function function1 = (s)->{return s;};
System.out.println(function.apply("sfaf"));
}
}
(2)断定式接口
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
package com.gykj;
import java.util.function.Predicate;
/**
* 断定式接口:有一个输入参数,返回值只能是布尔值!
*/
public class PredicateDemo {
public static void main(String[] args) {
Predicate<String> predicate = new Predicate<String>(){
@Override
public boolean test(String o) {
return o.isEmpty();
}
};
Predicate<String> predicate1 = (s)->{return s.isEmpty();};
System.out.println(predicate1.test("123"));
}
}
(3)消费型接口
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
package com.gykj;
import java.util.function.Consumer;
/**
* 消费型解耦:只有输入,没有返回值
*/
public class ProductDemo {
public static void main(String[] args) {
Consumer<String> consumer = new Consumer<String>(){
@Override
public void accept(String s) {
System.out.println(s);
}
};
Consumer<String> consumer1 = (s)->{
System.out.println("aaavvvv");;};
consumer1.accept("aaaaa");
}
}
(4)供给型接口
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
package com.gykj;
import org.omg.CORBA.INTERNAL;
import java.util.function.Supplier;
//供给型接口,没有输出,只有返回值
public class SupplierDemo {
public static void main(String[] args) {
Supplier supplier = new Supplier<Integer>(){
@Override
public Integer get() {
System.out.println("get()");
return 1024;
}
};
Supplier supplier1 = ()->{
System.out.println("get()");
return 1024;
};
System.out.println(supplier1.get());
}
}
15、stream流式计算
16、forkjoin
大任务拆分成小任务
特点:工作窃取
package com.gykj;
import java.util.concurrent.RecursiveTask;
/**
* 求和计算的任务
* 如何使用forkjoin
* forkjoinPool通过他来执行
* 计算任务forkjoinPool.executor(ForkJoinTask task)
* 计算类要继承ForkJoinTask
*/
public class ForkJoinDemo extends RecursiveTask<Long> {
private Long start;
private Long end;
//临界值
private Long temp = 100000L;
public ForkJoinDemo(Long start,Long end){
this.start = start;
this.end = end;
}
//计算方法
@Override
protected Long compute() {
if((end-start)<temp){
Long sum = 0L;
for(Long i = start;i<=end;i++){
sum+=i;
}
return sum;
}else {
//forkjoin递归
long middle = (start+end)/2;//中间值
ForkJoinDemo task1 = new ForkJoinDemo(start,middle);
task1.fork();//拆分任务,把任务压入线程队列
ForkJoinDemo task2 = new ForkJoinDemo(middle+1,end);
task2.fork();
return task1.join()+task2.join();
}
}
}
package com.gykj;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;
public class ForkTest {
public static void main(String[] args) throws ExecutionException,InterruptedException {
// test1();//sum=500000000500000000, time=23716
// test2();//sum=500000000500000000, time=16125
test3();//sum=500000000500000000, time=1396
}
public static void test1(){
Long sum = 0L;
long start = System.currentTimeMillis();
for(Long i = 1L;i<=10_0000_0000;i++){
sum+=i;
}
long end = System.currentTimeMillis();
System.out.println("sum="+sum+", time="+(end-start));
}
public static void test2() throws ExecutionException,InterruptedException {
// Long sum = 0L;
long start = System.currentTimeMillis();
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoinDemo(0L,10_0000_0000L);
ForkJoinTask<Long> submit = forkJoinPool.submit(task);//提交任务
Long sum = submit.get();
long end = System.currentTimeMillis();
System.out.println("sum="+sum+", time="+(end-start));
}
public static void test3(){
long start = System.currentTimeMillis();
//Stream并行流
long sum = LongStream.rangeClosed(0L,10_0000_0000L).parallel().reduce(0,Long::sum);
long end = System.currentTimeMillis();
System.out.println("sum="+sum+", time="+(end-start));
}
}
17 异步回调
package com.gykj;
import org.omg.PortableInterceptor.INACTIVE;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
* 异步调用:CompletableFuture
* 异步执行
* 成功回调
* 失败回调
*/
public class FutrueDemo {
public static void main(String[] args) throws ExecutionException,InterruptedException {
//没有返回值的runAsSync 异步毁掉
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
try {
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"runAdSync=>void");
});
System.out.println("1111");
completableFuture.get();//获取阻塞执行结果
//有返回值的supplyAsync 异步回调
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+"supplyAsync=>Integer");
int i=10/0;
return 1024;
});
System.out.println(completableFuture.whenComplete((t,u)->{
System.out.println("t=>"+t);
System.out.println("u=>"+u);
}).exceptionally((e)->{
System.out.println(e.getMessage());
return 233;//可以获取错误的返回信息
}).get());
}
}
18.volatile
(1)保证可见性
package com.gykj;
import java.util.concurrent.TimeUnit;
public class JMMDemo {
private volatile static int num = 0;
public static void main(String[] args) {
new Thread(()->{
while (num==0){
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
num = 1;
System.out.println(num);
}
}
(2)不保证原子性
package com.gykj;
public class JMMDemo2 {
private volatile static int num = 0;
public static void add(){
num++;
}
public static void main(String[] args) {
for (int i=1; i<=20;i++){
new Thread(()->{
for(int j=0;j<1000;j++){
add();
}
}).start();
}
while (Thread.activeCount()>2){
Thread.yield();
}
System.out.println(Thread.currentThread()+" "+num);
}
}
如何在不使用lock和synchronized情况下保证正确
package com.gykj;
import java.util.concurrent.atomic.AtomicInteger;
public class JMMDemo2 {
private volatile static AtomicInteger num = new AtomicInteger();
public static void add(){
// num++;
num.getAndIncrement();
}
public static void main(String[] args) {
for (int i=1; i<=20;i++){
new Thread(()->{
for(int j=0;j<1000;j++){
add();
}
}).start();
}
while (Thread.activeCount()>2){
Thread.yield();
}
System.out.println(Thread.currentThread()+" "+num);
}
}
19、单例模式
(1)饿汉式模式
package com.gykj.single;
//饿汉式单例
public class Hungry {
//弊端,可能会浪费时间
private byte[] data1 = new byte[1024*1024];
private byte[] data2 = new byte[1024*1024];
private byte[] data3 = new byte[1024*1024];
private byte[] data4 = new byte[1024*1024];
private Hungry{}
private final static Hungry HUNGRY = new Hungry();
public final static Hungry getInstance(){
return HUNGRY;
}
}
(2)懒汉式模式
package com.gykj.single;
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"ok");
}
private static LazyMan lazyMan;
//双重检测锁模式 懒汉式单例 DCL懒汉式
private static LazyMan getInstance(){
if(lazyMan == null){
synchronized (LazyMan.class){
if(lazyMan == null){
lazyMan = new LazyMan();
/**
* new LazyMan 不是一个原子操作
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把这个对象指向这个空间
*
* 123
* 132 //此时lazyMan还没有完成构造
*/
}
}
}
return lazyMan;
}
public static void main(String[] args) {
for (int i=0;i<10;i++){
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}
}
(3)内部类
package com.gykj.single;
public class Holder {
private Holder(){}
private static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER = new Holder();
}
}
通过静态内部类的方式实现单例模式是线程安全的,同时静态内部类不会在Singleton类加载时就加载,而是在调用getInstance()方法时才进行加载,达到了懒加载的效果。
似乎静态内部类看起来已经是最完美的方法了,其实不是,可能还存在反射攻击或者反序列化攻击。且看如下代码:
public static void main(String[] args) throws Exception {
Singleton singleton = Singleton.getInstance();
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton newSingleton = constructor.newInstance();
System.out.println(singleton == newSingleton);
}
(4)枚举
package com.gykj.single;
import org.omg.CORBA.PUBLIC_MEMBER;
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
通过反编译,他的构造参数并不是无参,而是有参
20 CAS
package com.gykj;
import java.util.concurrent.atomic.AtomicInteger;
public class CASDemo {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2021);
System.out.println(atomicInteger.compareAndSet(2021,2022));
System.out.println(atomicInteger.get());
System.out.println(atomicInteger.compareAndSet(2021,2022));
System.out.println(atomicInteger.get());
}
}
//调用了unsafe方法 CAS是CPU的并发原语
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//自旋锁
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
CAS:比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作 ,如果不是就一直循环
缺点:
循环会耗时
一次性只能保证一个共享变量的原子性
ABA问题
21、原子问题
package com.gykj;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;
public class CASDemo2 {
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1,1);
public static void main(String[] args) {
new Thread(()->{
int stamp = atomicStampedReference.getStamp();
System.out.println("a1=>"+stamp);
try {
TimeUnit.SECONDS.sleep(5);
}catch (InterruptedException e){
e.printStackTrace();
}
atomicStampedReference.compareAndSet(1,2,
atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
System.out.println("a2=>"+atomicStampedReference.getStamp());
atomicStampedReference.compareAndSet(2,1,
atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
System.out.println("a3=>"+atomicStampedReference.getStamp());
},"a").start();
new Thread(()->{
int stamp = atomicStampedReference.getStamp();//获得版本号
System.out.println("b1=>"+stamp);
try {
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(atomicStampedReference.compareAndSet(1,6, stamp,stamp+1));
System.out.println("b2=>"+atomicStampedReference.getStamp());
},"b").start();
}
}
注:Integer使用了对象缓存机制,默认范围为-128-127,推荐使用静态工厂方法valueOf获取对象实例,而不是new,因为valueOf使用缓存,而new一定会创建新的对象分配新的内存空间
排查死锁问题
使用jps -l 定位进程号
使用jstack 进程号 找到死锁问题