JUC并发编程总结(二)
- 前言:此总结更接近于使用和回顾juc内容。如果需要深入研究底层,请看源码或者官网文档。
函数接口、流式计算
四大函数式接口
Predicate
函数式接口,断言型,返回true/false
Function
函数式接口,函数型,有输入输出。Consumer
函数式接口,消费型,有输入输出。Supplier
函数式接口,供给型,无输入有输出。
- Predicate,重写
test
方法。提供两种效果一样的实现方式。Predicate predicate =new Predicate<String>() { @Override public boolean test(String o) { return false; } }; Predicate predicate1=(str)->{return false;}; System.out.println(predicate.test("0"));
- Function,重写
apply
方法。提供两种效果一样的实现方式。第一个是传入参数,第二个是返回值。Function function =new Function<Integer,String> (){ @Override public String apply(Integer o) { return o+""; } }; Function function1=(str)->{return str;}; System.out.println(function1.apply(5));
- Consumer,重写
accept
方法。提供两种效果一样的实现方式。Consumer consumer=new Consumer<String>() { @Override public void accept(String o) { System.out.println(o); } }; Consumer consumer1 =(str)->{ System.out.println(str);}; consumer1.accept("消费者接口被调用");
- Supplier,重写
get
方法。提供两种效果一样的实现方式。Supplier supplier=new Supplier<Integer>() { @Override public Integer get() { return null; } }; Supplier supplier1 =()->{System.out.println("接口被调用"); return "aaa";}; System.out.println( supplier1.get());
流式计算stream
- 流式计算常用于计算大的数据量,效率非常高。是常规计算效率的十倍。
- 示例:
public static void main(String[] args) { List<User> list =new ArrayList<>(); for (int i = 0; i <6 ; i++) { User user=new User(i,i+"娃",i); list.add(user); } list.stream() .filter(u->{return u.getId()%2==0;}) .filter(u->{return u.getAge()>2;}) .map(u->{return u.getName().replace("娃","wa");}) .sorted((uu1,uu2)->{return uu2.compareTo(uu1);}) .limit(1) .forEach(System.out::println); }
Forkjoin
工作模型
注意事项
- 使用
- 使用
ForkJoinPool
来执行分段任务。 - 计算任务
forkJoinPool.submit(task)
- 计算类要继承
ForkJoinTask
,重新compute
方法。
- 示例 :分段计算任务。
class ForkJoinDemo extends RecursiveTask<Long>{ private Long temp =1000L; private Long start; private Long end; 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 { 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(); } } } public class Demo08Forkjoin { public static void main(String[] args) throws ExecutionException, InterruptedException { Long start = System.currentTimeMillis(); //使用forkjoin ForkJoinPool forkJoinPool=new ForkJoinPool(); ForkJoinTask task =new ForkJoinDemo(0L,10000000L); ForkJoinTask submit =forkJoinPool.submit(task); Long sum = (Long) submit.get(); Long end = System.currentTimeMillis(); System.out.println(end-start+":"+sum); Long start1 = System.currentTimeMillis(); //不使用 Long sum1=0L; for (Long i = 0L; i <=10000000L ; i++) { sum1+=i; } Long end1 = System.currentTimeMillis(); System.out.println(end1-start1+":"+sum1); } }
异步
- CompletableFuture和函数接口一样也提供了
supplyAsync()
/runAsync
等方法。使用时选择正确的方法。 - 像JS和Promise那样执行异步任务。
CompletableFuture<Integer> completableFuture=CompletableFuture.supplyAsync(()->{ try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("异步任务执行完毕"); return 500; }); System.out.println("主线程任务"); completableFuture.get(); int a = completableFuture.whenComplete((t,u)->{ System.out.println("正确执行时返回结果:"+t); System.out.println("正确执行时返回结果:"+u); }).exceptionally((e)->{ return 233; }).get(); System.out.println(a);
JMM到单例模式
1. 对Volatile关键字的理解
volatile
是java虚拟机提供的轻量级同步机制。
- 保证可见性
- 不保证原子性
- 禁止指令重排
- 通知其他线程变量已经更改。
2. JMM:java内存模型
- 保证可见性:
- 不保证原子性 :多个线程修改带有volatile关键字的变量时仍然会出问题。
- 禁止指令重排 (了解更多请查看相关文档)
- 保证特定操作有序
- 保证变量内存可见性。
3. 彻底玩转单例模式
CAS:比较并交换
1. 理解CAS
- 缺点
- 循环耗时
- 一次保证一个共享变量原子性
- ABA问题
2. 原子引用
各种锁
公平锁、非公平锁
- 关键是能不能插队的问题
- 可重入锁构造方法
可重入锁(递归锁)
- 得到大门锁,自然得到房间锁。
- 注意sms里面调用了call()
自旋锁
死锁问题排查方案
- 使用
jps- a
进行进程号定位:
- 使用
jstack 进程号
进行定位
AQS(AbstractQueuedSynchronizer)
- 此类事锁的实现原理。
手动写一个锁。
public class Demo11AQS {
public static void main(String[] args) throws InterruptedException {
final Integer[] sum = {0};
Lock lock =new MyLock();
Thread[] a= new Thread[500];
for (int j = 0; j <500 ; j++) {
a[j] = new Thread(()->{
lock.lock();
sum[0]++;
lock.unlock();
});
a[j].start();
}
for (Thread item:a){
item.join();
}
System.out.println(sum[0]);
}
static void add(Integer a,Integer b){
a=a+b;
}
}
class MyLock implements Lock {
private Sync sync =new Sync();
@Override
public void lock() {
sync.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
sync.release(1);
}
@Override
public Condition newCondition() {
return null;
}
private class Sync extends AbstractQueuedSynchronizer{
@Override
protected boolean tryAcquire(int arg) {
assert arg==1;
if (compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg) {
assert arg==1;
if (! isHeldExclusively()) try {
throw new IllegalAccessException();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
setExclusiveOwnerThread(null);
setState(0);
return true;
}
@Override
protected boolean isHeldExclusively() {
return getExclusiveOwnerThread()==Thread.currentThread();
}
}
}
Reference
- https://www.jianshu.com/p/c366c9238bb8