java8与并行
来源:互联网 发布:mac恢复出厂系统版本 编辑:程序博客网 时间:2024/06/07 03:09
申明式的编程方式
不需要提供明确的指令操作,所有的细节指令被程序库封装,只要提出要求,申明用意
- public class Test1 {
- public static void main(String[] args) {
- int[]ary={1,2,5,2};
- for (int i = 0; i < ary.length; i++) {
- System.out.println(ary[i]);
- }
- Arrays.stream(ary).forEach(System.out::println);
- }
- }
public class Test1 { public static void main(String[] args) { int[]ary={1,2,5,2}; for (int i = 0; i < ary.length; i++) { System.out.println(ary[i]); } Arrays.stream(ary).forEach(System.out::println); }}不变的对象
几乎所有传递的对象都不会被轻易修改
- public class Test1 {
- public static void main(String[] args) {
- int[]ary={1,2,5,2};
- Arrays.stream(ary).map((x)->x=x+1).forEach(System.out::println);
- Arrays.stream(ary).forEach(System.out::println);
- }
- }
public class Test1 { public static void main(String[] args) { int[]ary={1,2,5,2}; Arrays.stream(ary).map((x)->x=x+1).forEach(System.out::println); Arrays.stream(ary).forEach(System.out::println); }}2
3
6
3
1
2
5
2
易于并行
因为对象是不变的,不必担心多线程会写坏对象,不必同步和锁
代码更少
判断奇数加1
- public class Test1 {
- static int[]arr={1,2,3,45,6};
- public static void main(String[] args) {
- for(int i=0;i<arr.length;i++){
- if(arr[i]%2!=0){
- arr[i]++;
- }
- System.out.println(arr[i]);
- }
- Arrays.stream(arr).map(x->(x%2==0?x:x+1)).forEach(System.out::println);
- }
- }
public class Test1 { static int[]arr={1,2,3,45,6}; public static void main(String[] args) { for(int i=0;i<arr.length;i++){ if(arr[i]%2!=0){ arr[i]++; } System.out.println(arr[i]); } Arrays.stream(arr).map(x->(x%2==0?x:x+1)).forEach(System.out::println); }}FunctionalInterface注释
函数式接口,只定义了单一抽象方法的接口
- @FunctionalInterface
- public static interface IntHandler{
- void handle(int i);
- }
@FunctionalInterface public static interface IntHandler{ void handle(int i); }表明它是函数式接口,只包含一个抽象方法,但可以有其他方法,被Object实现的方法都不是抽象方法
接口默认方法
java8可以包含实例方法,需要用default关键字
- @FunctionalInterface
- public static interface IntHandler{
- void handle(int i);
- default void run(){}
- }
@FunctionalInterface public static interface IntHandler{ void handle(int i); default void run(){} }可以多实现,但会有多继承相同的问题
俩接口有相同实例方法,子类就会报错,需要指定
- public interface IHorse {
- void eat();
- default void run(){
- System.out.println(”hourse run”);
- }
- }
- public interface IAbimal {
- void eat();
- default void breath(){
- System.out.println(”breath”);
- }
- default void run(){
- System.out.println(”abimal run”);
- }
- }
- public class Mule implements IHorse,IAbimal{
- @Override
- public void eat() {
- System.out.println(”mule eat”);
- }
- //重新实现run方法,指定
- @Override
- public void run() {
- IAbimal.super.run();
- }
- public static void main(String[] args) {
- Mule m = new Mule();
- m.eat();
- m.run();
- m.breath();
- }
- }
public interface IHorse { void eat(); default void run(){ System.out.println("hourse run"); }}public interface IAbimal { void eat(); default void breath(){ System.out.println("breath"); } default void run(){ System.out.println("abimal run"); }}public class Mule implements IHorse,IAbimal{ @Override public void eat() { System.out.println("mule eat"); } //重新实现run方法,指定 @Override public void run() { IAbimal.super.run(); } public static void main(String[] args) { Mule m = new Mule(); m.eat(); m.run(); m.breath(); }}比方java.util.Comparator接口,增加了default方法,用于多个比较器的整合
- default Comparator<T> thenComparing(Comparator<? super T> other) {
- Objects.requireNonNull(other);
- return (Comparator<T> & Serializable) (c1, c2) -> {
- int res = compare(c1, c2);
- return (res != 0) ? res : other.compare(c1, c2);
- };
- }
default Comparator<T> thenComparing(Comparator<? super T> other) { Objects.requireNonNull(other); return (Comparator<T> & Serializable) (c1, c2) -> { int res = compare(c1, c2); return (res != 0) ? res : other.compare(c1, c2); }; }先比较字符串长度,在按照大小写不敏感的字母顺序排列
- Comparator<String>cmp = Comparator.comparingInt(String::length).thenComparing(String.CASE_INSENSITIVE_ORDER);
Comparator<String>cmp = Comparator.comparingInt(String::length).thenComparing(String.CASE_INSENSITIVE_ORDER);lambda表达式
即匿名表达式,是一段没有函数名的函数体,可以作为参数直接传递给相关的调用者
- List<Integer> numbers = Arrays.asList(1,2,3,4,5);
- numbers.forEach((Integer value)->System.out.println(value));
List<Integer> numbers = Arrays.asList(1,2,3,4,5); numbers.forEach((Integer value)->System.out.println(value));类似匿名内部类,简单的描述了应该执行的代码段
可以访问外部的局部变量,如下,外部的变量必须申明为final,保证不可变,合法的访问,但默认会加final,不加也会默认
- final int num =2;
- Function<Integer, Integer>stringConverter = (from)->from*num;
- System.out.println(stringConverter.apply(3));
final int num =2; Function<Integer, Integer>stringConverter = (from)->from*num; System.out.println(stringConverter.apply(3));num++会报错
方法引用
通过类名或方法名定位到一个静态方法或者实例方法
静态方法引用:InnerClassName::methodName
实例上的实例方法引用:instanceReference::methodName
超类上的实例方法引用:super::methodName
类型上的实例方法引用:CLassName::methodName
构造方法引用:Class::new
数组构造方法引用:TypeName[]::new
方法引用使用::定义,::前半部分表示类名或实例名,后半部分表示方法名,是构造方法就用new
- public class InstanceMethodRef {
- static class User{
- int i;
- String string;
- public User(int i, String string) {
- this.i=i;
- this.string=string;
- }
- public int getI() {
- return i;
- }
- public void setI(int i) {
- this.i = i;
- }
- public String getString() {
- return string;
- }
- public void setString(String string) {
- this.string = string;
- }
- }
- public static void main(String[] args) {
- List<User> users = new ArrayList<>();
- for(int i=1;i<10;i++){
- users.add(new User(i,“billy”+Integer.toString(i)));
- }
- users.stream().map(User::getString).forEach(System.out::println);
- }
- }
public class InstanceMethodRef { static class User{ int i; String string; public User(int i, String string) { this.i=i; this.string=string; } public int getI() { return i; } public void setI(int i) { this.i = i; } public String getString() { return string; } public void setString(String string) { this.string = string; } } public static void main(String[] args) { List<User> users = new ArrayList<>(); for(int i=1;i<10;i++){ users.add(new User(i,"billy"+Integer.toString(i))); } users.stream().map(User::getString).forEach(System.out::println); }}
使用静态方法或者调用明确,流内的元素自动作为参数使用,函数引用表示实例方法,且不存在调用目标,流内元素自动作为调用目标
如果一个类中存在同名的实例方法和静态函数,编译器既可以选择同名的实例方法,将流内元素作为调用目标,也可以使用静态方法,将流元素作为参数比方Double
public String toString()
public static String toString(double d)
方法引用也可以直接调用构造函数
- static class ConstrMethodRef{
- @FunctionalInterface
- interface UserFactory<U extends User>{
- U create(int id,String name);
- }
- static UserFactory<User> uf = User::new;
- }
static class ConstrMethodRef{ @FunctionalInterface interface UserFactory<U extends User>{ U create(int id,String name); } static UserFactory<User> uf = User::new; }函数式接口,User::new创建接口实例时,系统会根据UserFactory.create()的函数签名选择合适的User构造函数,
这里是public User(int i, String string),创建UserFactory实例后,对UserFactory.create()的调用,都会委托给User的实际构造函数进行
函数式编程
- public class Test2 {
- static int[]arr={1,2,3,45,6};
- public static void main(String[] args) {
- for (int i : arr) {
- System.out.println(i);
- }
- Arrays.stream(arr).forEach(new IntConsumer() {
- @Override
- public void accept(int value) {
- System.out.println(value);
- }
- });
- }
- }
public class Test2 { static int[]arr={1,2,3,45,6}; public static void main(String[] args) { for (int i : arr) { System.out.println(i); } Arrays.stream(arr).forEach(new IntConsumer() { @Override public void accept(int value) { System.out.println(value); } }); }}
Arrays.stream()返回一个流对象,类似集合或数组,流对象也是一个对象的集合,有遍历处理流内元素的功能
IntConsumer()接口用于对每个流内对象进行处理,当前流是IntStream,即装有Integer元素的流,foreach会挨个将流内元素送入接口处理
foreach的参数是可以从上下文中推导的,以下不再手动推导,省略接口名
- Arrays.stream(arr).forEach((final int x)->{System.out.println(x);});
Arrays.stream(arr).forEach((final int x)->{System.out.println(x);});参数类型也可以推导
- Arrays.stream(arr).forEach((x)->{System.out.println(x);});
Arrays.stream(arr).forEach((x)->{System.out.println(x);});去除花括号
- Arrays.stream(arr).forEach((x)->System.out.println(x));
Arrays.stream(arr).forEach((x)->System.out.println(x));lambda表达式,由->分割,左面表示参数,右面实现体
方法引用
- Arrays.stream(arr).forEach(System.out::println);
Arrays.stream(arr).forEach(System.out::println);lambda表达式不仅可以简化匿名内部类的编写,还可以使用流式api对各种组件进行更自由的装配
输出俩次元素
- IntConsumer outprintln = System.out::println;
- IntConsumer errprintln = System.err::println;
- Arrays.stream(arr).forEach(outprintln.andThen(errprintln));
IntConsumer outprintln = System.out::println; IntConsumer errprintln = System.err::println; Arrays.stream(arr).forEach(outprintln.andThen(errprintln));使用并行流过滤数据
- public class PrimeUtil {
- public static boolean isPrime(int number){
- int tmp = number;
- if(tmp<2){
- return false;
- }
- for(int i=2;i<tmp;i++){
- if(tmp%i==0){
- return false;
- }
- }
- return true;
- }
- public static void main(String[] args) {
- //串行,首先生成1到1000000的数字流,接着使用过滤函数,只选择所有的质数,最后统计数量
- //IntStream.range(1, 1000000).filter(PrimeUtil::isPrime).count();
- //并行
- IntStream.range(1, 1000000).parallel().filter(PrimeUtil::isPrime).count();
- }
- }
public class PrimeUtil { public static boolean isPrime(int number){ int tmp = number; if(tmp<2){ return false; } for(int i=2;i<tmp;i++){ if(tmp%i==0){ return false; } } return true; } public static void main(String[] args) { //串行,首先生成1到1000000的数字流,接着使用过滤函数,只选择所有的质数,最后统计数量 //IntStream.range(1, 1000000).filter(PrimeUtil::isPrime).count(); //并行 IntStream.range(1, 1000000).parallel().filter(PrimeUtil::isPrime).count(); }}从集合中得到并行流
- //使用stream得到一个流
- double ave = ss.stream().mapToInt(s->s.score).average().getAsDouble();
- //并行化
- double ave = ss.parallelStream().mapToInt(s->s.score).average().getAsDouble();
//使用stream得到一个流 double ave = ss.stream().mapToInt(s->s.score).average().getAsDouble(); //并行化 double ave = ss.parallelStream().mapToInt(s->s.score).average().getAsDouble();并行排序
Arrays.sort()串行排序
并行排序
- int[] arrr = new int[10000];
- Arrays.parallelSort(arrr);
int[] arrr = new int[10000]; Arrays.parallelSort(arrr);赋值
- Random r = new Random();
- //串行
- Arrays.setAll(arr, (i)->r.nextInt());
- //并行
- Arrays.parallelSetAll(arr, (i)->r.nextInt());
Random r = new Random(); //串行 Arrays.setAll(arr, (i)->r.nextInt()); //并行 Arrays.parallelSetAll(arr, (i)->r.nextInt());CompletableFuture
可以作为函数调用的契约,向它请求一个数据,数据没准备好,请求线程会等待,这里可以手动设置完成状态
- public class CompletableFutureTest {
- static class AskThread implements Runnable{
- CompletableFuture<Integer> re = null;
- public AskThread(CompletableFuture<Integer> re) {
- this.re = re;
- }
- @Override
- public void run() {
- int myRe = 0;
- try {
- myRe = re.get()*re.get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- System.out.println(myRe);
- }
- public static void main(String[] args) throws InterruptedException {
- final CompletableFuture<Integer> future = new CompletableFuture<>();
- new Thread(new AskThread(future)).start();
- Thread.sleep(1000);
- future.complete(60);
- }
- }
- }
public class CompletableFutureTest { static class AskThread implements Runnable{ CompletableFuture<Integer> re = null; public AskThread(CompletableFuture<Integer> re) { this.re = re; } @Override public void run() { int myRe = 0; try { myRe = re.get()*re.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println(myRe); } public static void main(String[] args) throws InterruptedException { final CompletableFuture<Integer> future = new CompletableFuture<>(); new Thread(new AskThread(future)).start(); Thread.sleep(1000); future.complete(60); } }}异步执行任务
- public class CompletableFutureSync {
- public static Integer calc(Integer para){
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return para*para;
- }
- public static void main(String[] args) throws InterruptedException, ExecutionException {
- final CompletableFuture<Integer> future = CompletableFuture.supplyAsync(()->calc(50));
- System.out.println(future.get());
- }
- }
public class CompletableFutureSync { public static Integer calc(Integer para){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return para*para; } public static void main(String[] args) throws InterruptedException, ExecutionException { final CompletableFuture<Integer> future = CompletableFuture.supplyAsync(()->calc(50)); System.out.println(future.get()); }}supplyAsync()函数中,会在一个新的线程中执行传入的参数,会立即返回,没计算完,get方法会等待
runAsync()用于没有返回值的场景
都可以指定线程池,也可以用默认线程池,但主线程退出,立即退出系统
流式调用
- public class CompletableFutureSync {
- public static Integer calc(Integer para){
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return para*para;
- }
- public static void main(String[] args) throws InterruptedException, ExecutionException {
- final CompletableFuture<Void> future = CompletableFuture.supplyAsync(()->calc(50))
- .thenApply((i)->Integer.toString(i)).thenApply((src)->”\”“+src+“\”“).thenAccept(System.out::println);
- future.get();
- }
- }
public class CompletableFutureSync { public static Integer calc(Integer para){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return para*para; } public static void main(String[] args) throws InterruptedException, ExecutionException { final CompletableFuture<Void> future = CompletableFuture.supplyAsync(()->calc(50)) .thenApply((i)->Integer.toString(i)).thenApply((src)->"\""+src+"\"").thenAccept(System.out::println); future.get(); }}连续使用流式调用对任务的处理结果进行加工
最后的get()方法目的是等待函数执行完成,不使用,因为是异步的,主线程会退出,然后其他线程也会退出,导致方法无法正常执行
异常处理
- public class CompletableFutureSync {
- public static Integer calc(Integer para){
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return para*para;
- }
- public static void main(String[] args) throws InterruptedException, ExecutionException {
- CompletableFuture<Void> future = CompletableFuture.supplyAsync(()->calc(50))
- .exceptionally(ex->{
- System.out.println(ex.toString());
- return 0;
- })
- .thenApply((i)->Integer.toString(i)).thenApply((src)->”\”“+src+“\”“).thenAccept(System.out::println);
- future.get();
- }
- }
public class CompletableFutureSync { public static Integer calc(Integer para){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return para*para; } public static void main(String[] args) throws InterruptedException, ExecutionException { CompletableFuture<Void> future = CompletableFuture.supplyAsync(()->calc(50)) .exceptionally(ex->{ System.out.println(ex.toString()); return 0; }) .thenApply((i)->Integer.toString(i)).thenApply((src)->"\""+src+"\"").thenAccept(System.out::println); future.get(); }}组合多个CompletableFuture
- public <U> CompletableFuture<U> thenCompose(
- Function<? super T, ? extends CompletionStage<U>> fn) {
- return uniComposeStage(null, fn);
- }
public <U> CompletableFuture<U> thenCompose( Function<? super T, ? extends CompletionStage<U>> fn) { return uniComposeStage(null, fn); }一种是使用thenCompose将执行结果传给下一个CompletableFuture
- public class CompletableFutureSync {
- public static Integer calc(Integer para){
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return para*para;
- }
- public static void main(String[] args) throws InterruptedException, ExecutionException {
- CompletableFuture<Void> future = CompletableFuture.supplyAsync(()->calc(50))
- .thenCompose((i)->CompletableFuture.supplyAsync(()->calc(i)))
- .thenApply((src)->”\”“+src+“\”“).thenAccept(System.out::println);
- future.get();
- }
- }
public class CompletableFutureSync { public static Integer calc(Integer para){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return para*para; } public static void main(String[] args) throws InterruptedException, ExecutionException { CompletableFuture<Void> future = CompletableFuture.supplyAsync(()->calc(50)) .thenCompose((i)->CompletableFuture.supplyAsync(()->calc(i))) .thenApply((src)->"\""+src+"\"").thenAccept(System.out::println); future.get(); }}另一种是thenCombine()方法
先执行当前的和其他的,执行完后把结果传给BiFunction
- public <U,V> CompletableFuture<V> thenCombine(
- CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn) {
- return biApplyStage(null, other, fn);
- }
public <U,V> CompletableFuture<V> thenCombine( CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn) { return biApplyStage(null, other, fn); }把俩个结果累加
- public class CompletableFutureSync {
- public static Integer calc(Integer para){
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return para*para;
- }
- public static void main(String[] args) throws InterruptedException, ExecutionException {
- CompletableFuture<Integer> future1= CompletableFuture.supplyAsync(()->calc(50));
- CompletableFuture<Integer> future2= CompletableFuture.supplyAsync(()->calc(25));
- CompletableFuture<Void> future3=future1.thenCombine(future2, (i,j)->(i+j))
- .thenApply((src)->”\”“+src+“\”“).thenAccept(System.out::println);
- future3.get();
- }
- }
public class CompletableFutureSync { public static Integer calc(Integer para){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return para*para; } public static void main(String[] args) throws InterruptedException, ExecutionException { CompletableFuture<Integer> future1= CompletableFuture.supplyAsync(()->calc(50)); CompletableFuture<Integer> future2= CompletableFuture.supplyAsync(()->calc(25)); CompletableFuture<Void> future3=future1.thenCombine(future2, (i,j)->(i+j)) .thenApply((src)->"\""+src+"\"").thenAccept(System.out::println); future3.get(); }}读写锁的改进,StampedLock
原本读写锁读锁会堵塞写锁,使用的是悲观策略,有大量的读线程,也可能导致写线程的饥饿
这个lock提供了乐观的读策略,类似无锁操作
- public class Point {
- private double x,y;
- private final StampedLock s1 = new StampedLock();
- void move(double deltax,double deltay){//排他锁
- long stamp = s1.writeLock();
- try {
- x+=deltax;
- y+=deltay;
- } finally{
- s1.unlockWrite(stamp);
- }
- }
- double distanceFromOrigin(){//只读方法
- long stamp = s1.tryOptimisticRead();//尝试一次乐观锁,返回一个类似时间戳的邮戳整数
- double currentx =x,currenty=y;
- if(!s1.validate(stamp)){//判断是否被修改过
- stamp = s1.readLock();
- try {
- currentx=x;
- currenty=y;
- } finally{
- s1.unlockRead(stamp);
- }
- }
- return Math.sqrt(currentx*currentx+currenty+currenty);
- }
- }
public class Point { private double x,y; private final StampedLock s1 = new StampedLock(); void move(double deltax,double deltay){//排他锁 long stamp = s1.writeLock(); try { x+=deltax; y+=deltay; } finally{ s1.unlockWrite(stamp); } } double distanceFromOrigin(){//只读方法 long stamp = s1.tryOptimisticRead();//尝试一次乐观锁,返回一个类似时间戳的邮戳整数 double currentx =x,currenty=y; if(!s1.validate(stamp)){//判断是否被修改过 stamp = s1.readLock(); try { currentx=x; currenty=y; } finally{ s1.unlockRead(stamp); } } return Math.sqrt(currentx*currentx+currenty+currenty); }}此处把乐观锁升级成悲观锁,也可以像CAS操作一样在死循环中不断使用乐观锁
StampedLock的内部实现类似于CAS操作的死循环反复尝试策略,挂起线程时,使用的是Unsafe.park()函数,这个函数遇到线程中断时会直接返回,不会抛异常,导致堵塞在park()上的线程被中断后会再次进入循环,退出条件得不到满足,会疯狂占用CPU
没遇到疯狂占用CPU的情况
- public class StampedLockCPUDemo {
- static Thread[]holdCpuThreads = new Thread[3];
- static final StampedLock lock = new StampedLock();
- public static void main(String[] args) throws InterruptedException {
- new Thread(){
- @Override
- public void run(){
- long readLong = lock.writeLock();
- LockSupport.parkNanos(600000000000000L);
- lock.unlockWrite(readLong);
- }
- }.start();
- Thread.sleep(100);
- for(int i=0;i<3;i++){
- holdCpuThreads[i]=new Thread(new HoldCPUReadThread());
- holdCpuThreads[i].start();
- }
- Thread.sleep(10000);
- //线程中断会占用CPU
- for(int i=0;i<3;i++){
- holdCpuThreads[i].interrupt();
- }
- }
- private static class HoldCPUReadThread implements Runnable{
- @Override
- public void run(){
- long lockr = lock.readLock();
- System.out.println(Thread.currentThread().getName()+”获取读锁”);
- lock.unlockRead(lockr);
- }
- }
- }
public class StampedLockCPUDemo { static Thread[]holdCpuThreads = new Thread[3]; static final StampedLock lock = new StampedLock(); public static void main(String[] args) throws InterruptedException { new Thread(){ @Override public void run(){ long readLong = lock.writeLock(); LockSupport.parkNanos(600000000000000L); lock.unlockWrite(readLong); } }.start(); Thread.sleep(100); for(int i=0;i<3;i++){ holdCpuThreads[i]=new Thread(new HoldCPUReadThread()); holdCpuThreads[i].start(); } Thread.sleep(10000); //线程中断会占用CPU for(int i=0;i<3;i++){ holdCpuThreads[i].interrupt(); } } private static class HoldCPUReadThread implements Runnable{ @Override public void run(){ long lockr = lock.readLock(); System.out.println(Thread.currentThread().getName()+"获取读锁"); lock.unlockRead(lockr); } }}内部实现是基于CLH锁的,这是个自旋锁,保证没有饥饿发生,保证先进先出的顺序,锁维护等待线程队列,所有申请锁,但没有成功的线程都记录在这个队列中,每一个节点(线程)保存一个标记位(locked),用于判断当前线程是否已经释放锁,当一个线程试图获得锁时,取得当前等待队列的尾部节点作为其前序节点,使用如下代码判断前序节点是否已经成功释放锁
- while (pred.locked){}
while (pred.locked){}
- /** Wait nodes */
- static final class WNode {
- volatile WNode prev;
- volatile WNode next;
- volatile WNode cowait; // 读节点列表
- volatile Thread thread; // 当可能被暂停时非空
- volatile int status; // 0, WAITING, or CANCELLED
- final int mode; // RMODE or WMODE
- WNode(int m, WNode p) { mode = m; prev = p; }
- }
- /** Head of CLH queue */
- private transient volatile WNode whead;
- /** Tail (last) of CLH queue */
- private transient volatile WNode wtail;
/** Wait nodes */ static final class WNode { volatile WNode prev; volatile WNode next; volatile WNode cowait; // 读节点列表 volatile Thread thread; // 当可能被暂停时非空 volatile int status; // 0, WAITING, or CANCELLED final int mode; // RMODE or WMODE WNode(int m, WNode p) { mode = m; prev = p; } } /** Head of CLH queue */ private transient volatile WNode whead; /** Tail (last) of CLH queue */ private transient volatile WNode wtail;WNode为链表的基本元素,每一个WNode表示一个等待线程,
- private transient volatile long state;//当前锁的等待状态
private transient volatile long state;//当前锁的等待状态倒数第八位表示写锁状态,该位为1,表示当前由写锁占用
乐观锁会执行如下操作
- public long tryOptimisticRead() {
- long s;
- return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
- }
public long tryOptimisticRead() { long s; return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L; }WBIT表示写锁状态位,值为0x80,成功,返回当前值,末尾7位清0,末尾7位表示当前正在读取的线程数量
乐观锁读后有线程申请写锁,state状态改变,设置写锁位为1,通过加上WBIT
- public long writeLock() {
- long s, next; // bypass acquireWrite in fully unlocked case only
- return ((((s = state) & ABITS) == 0L &&
- U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
- next : acquireWrite(false, 0L));
- }
public long writeLock() { long s, next; // bypass acquireWrite in fully unlocked case only return ((((s = state) & ABITS) == 0L && U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ? next : acquireWrite(false, 0L)); }
下述用于比较当前stamp和发生乐观锁时取得的stamp,不一致,乐观锁失败
- public boolean validate(long stamp) {
- U.loadFence();
- return (stamp & SBITS) == (state & SBITS);
- }
public boolean validate(long stamp) { U.loadFence(); return (stamp & SBITS) == (state & SBITS); }悲观读锁
- public long readLock() {
- long s = state, next; // bypass acquireRead on common uncontended case
- return ((whead == wtail && (s & ABITS) < RFULL &&
- U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
- next : acquireRead(false, 0L));
- }
public long readLock() { long s = state, next; // bypass acquireRead on common uncontended case return ((whead == wtail && (s & ABITS) < RFULL && U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ? next : acquireRead(false, 0L)); }悲观锁会设置state状态,将state加1,前提是读线程数量没有溢出,用于统计读线程数量,失败进入acquireRead()二次尝试锁读取,会自旋,通过CAS操作获取锁,失败,会启用CLH队列,将自己加入到队列,之后再进行自旋,获得读锁,进一步把自己cowait队列中的读线程全部激活(使用Unsafe.unpark()方法),依然无法获得读锁,使用Unsafe.unpark()挂起当前线程
acquireWrite类似acquireRead,释放锁与加锁相反
- public void unlockWrite(long stamp) {
- WNode h;
- if (state != stamp || (stamp & WBIT) == 0L)
- throw new IllegalMonitorStateException();
- state = (stamp += WBIT) == 0L ? ORIGIN : stamp;
- if ((h = whead) != null && h.status != 0)
- release(h);
- }
public void unlockWrite(long stamp) { WNode h; if (state != stamp || (stamp & WBIT) == 0L) throw new IllegalMonitorStateException(); state = (stamp += WBIT) == 0L ? ORIGIN : stamp; if ((h = whead) != null && h.status != 0) release(h); }将写标记位清0,state溢出,退回初始值,等待队列不为空,则从等待队列中激活一个线程,大部分是第一个线程继续执行
原子类的增强
更快的原子类,LongAdder
在java.util.concurrent.atomic包下,使用CAS指令
AtomicInteger等是在一个死循环中,不断尝试修改目标值,直到修改成功,竞争不激烈,修改成功的概率很高,否则,失败的概率很高,失败会多次循环尝试,影响性能
竞争激烈提高性能
1、热点分离,将竞争的数据进行分解
可以减小锁粒度,仿照ConcurrentHashMap,将AtomicInteger的内部核心数据value分离成一个数组,每个线程访问时,通过hash等算法映射到其中一个数字进行计算,最终的结果就是这个数组的求和累加
LongAddr也是这种思想,但它不会一开始就使用数组,先将所有数据都记录在一个base变量中,多线程修改base不冲突,没必要拓展成cell数组,冲突,就会初始化cell数组,使用新策略,如果在cell上更新依然发生冲突,系统会尝试创建新的cell,或将cell翻倍,减少冲突
- public void increment() {
- add(1L);
- }
- public void add(long x) {
- Cell[] as; long b, v; int m; Cell a;
- if ((as = cells) != null || !casBase(b = base, b + x)) {
- boolean uncontended = true;
- if (as == null || (m = as.length - 1) < 0 ||
- (a = as[getProbe() & m]) == null ||
- !(uncontended = a.cas(v = a.value, v + x)))
- longAccumulate(x, null, uncontended);
- }
- }
public void increment() { add(1L); } public void add(long x) { Cell[] as; long b, v; int m; Cell a; if ((as = cells) != null || !casBase(b = base, b + x)) { boolean uncontended = true; if (as == null || (m = as.length - 1) < 0 || (a = as[getProbe() & m]) == null || !(uncontended = a.cas(v = a.value, v + x))) longAccumulate(x, null, uncontended); } }开始cellsnull,数据会向base增加,如果对base操作冲突,设置冲突标记uncontented为true,接着如果cells数组不可用,,或者当前线程对应的cell为null,直接进入longAccumulate方法,否则会尝试使用CAS方法更新对应的cell数据,成功就退出,失败进入longAccumulate
- public class LongAdderDemo {
- private static final int MAX_THREADS=3;//线程数
- private static final int TASK_COUNT=3;//任务数
- private static final int TAEGET_COUNT=10000000;//目标总数
- private AtomicLong account = new AtomicLong(0L);//无锁的原子操作
- private LongAdder laccount = new LongAdder();//改进的无锁的原子操作
- private long count =0;
- static CountDownLatch cdlsync = new CountDownLatch(TASK_COUNT);
- static CountDownLatch cdlatomic = new CountDownLatch(TASK_COUNT);
- static CountDownLatch cdladdr = new CountDownLatch(TASK_COUNT);
- protected synchronized long inc(){//有锁的原子加法
- return count++;
- }
- protected synchronized long getCount(){//有锁的操作
- return count;
- }
- //有锁
- public class SyncThread implements Runnable{
- protected String name;
- private long starttime;
- LongAdderDemo out;
- public SyncThread(long starttime, LongAdderDemo out) {
- this.starttime = starttime;
- this.out = out;
- }
- @Override
- public void run() {
- long v= out.getCount();
- while(v<TAEGET_COUNT){//到达目标值前不断循环
- v=out.inc();
- }
- long endTime = System.currentTimeMillis();
- System.out.println(”SynchThread spend:”+(endTime-starttime)+“ms”+“v=”+v);
- cdlsync.countDown();
- }
- }
- //无锁
- public class AtomicThread implements Runnable{
- protected String name;
- private long starttime;
- public AtomicThread(long starttime) {
- this.starttime = starttime;
- }
- @Override
- public void run() {
- long v= account.get();
- while(v<TAEGET_COUNT){//到达目标值前不断循环
- v=account.incrementAndGet();//无锁的加法
- }
- long endTime = System.currentTimeMillis();
- System.out.println(”AtomicThread spend:”+(endTime-starttime)+“ms”+“v=”+v);
- cdlsync.countDown();
- }
- }
- public class LongAddrThread implements Runnable{
- protected String name;
- private long starttime;
- public LongAddrThread(long starttime) {
- this.starttime = starttime;
- }
- @Override
- public void run() {
- long v= laccount.sum();
- while(v<TAEGET_COUNT){//到达目标值前不断循环
- laccount.increment();
- v=laccount.sum();
- }
- long endTime = System.currentTimeMillis();
- System.out.println(”LongAddrThread spend:”+(endTime-starttime)+“ms”+“v=”+v);
- cdladdr.countDown();
- }
- }
- public void testAtomicLong() throws InterruptedException{
- ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREADS);
- long starttime = System.currentTimeMillis();
- LongAddrThread atomic = new LongAddrThread(starttime);
- for(int i=0;i<TASK_COUNT;i++){
- executorService.submit(atomic);
- }
- cdladdr.await();
- executorService.shutdown();
- }
- public void testAtomic() throws InterruptedException{
- ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREADS);
- long starttime = System.currentTimeMillis();
- AtomicThread atomic = new AtomicThread(starttime);
- for(int i=0;i<TASK_COUNT;i++){
- executorService.submit(atomic);
- }
- cdlatomic.await();
- executorService.shutdown();
- }
- public void testSync() throws InterruptedException{
- ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREADS);
- long starttime = System.currentTimeMillis();
- SyncThread sync = new SyncThread(starttime,this);
- for(int i=0;i<TASK_COUNT;i++){
- executorService.submit(sync);
- }
- cdlsync.await();
- executorService.shutdown();
- }
- public static void main(String[] args) throws InterruptedException {
- LongAdderDemo l1= new LongAdderDemo();
- LongAdderDemo l2= new LongAdderDemo();
- LongAdderDemo l3= new LongAdderDemo();
- l3.testAtomicLong();
- l1.testSync();
- l2.testAtomic();
- }
- }
public class LongAdderDemo { private static final int MAX_THREADS=3;//线程数 private static final int TASK_COUNT=3;//任务数 private static final int TAEGET_COUNT=10000000;//目标总数 private AtomicLong account = new AtomicLong(0L);//无锁的原子操作 private LongAdder laccount = new LongAdder();//改进的无锁的原子操作 private long count =0; static CountDownLatch cdlsync = new CountDownLatch(TASK_COUNT); static CountDownLatch cdlatomic = new CountDownLatch(TASK_COUNT); static CountDownLatch cdladdr = new CountDownLatch(TASK_COUNT); protected synchronized long inc(){//有锁的原子加法 return count++; } protected synchronized long getCount(){//有锁的操作 return count; } //有锁 public class SyncThread implements Runnable{ protected String name; private long starttime; LongAdderDemo out; public SyncThread(long starttime, LongAdderDemo out) { this.starttime = starttime; this.out = out; } @Override public void run() { long v= out.getCount(); while(v<TAEGET_COUNT){//到达目标值前不断循环 v=out.inc(); } long endTime = System.currentTimeMillis(); System.out.println("SynchThread spend:"+(endTime-starttime)+"ms"+"v="+v); cdlsync.countDown(); } } //无锁 public class AtomicThread implements Runnable{ protected String name; private long starttime; public AtomicThread(long starttime) { this.starttime = starttime; } @Override public void run() { long v= account.get(); while(v<TAEGET_COUNT){//到达目标值前不断循环 v=account.incrementAndGet();//无锁的加法 } long endTime = System.currentTimeMillis(); System.out.println("AtomicThread spend:"+(endTime-starttime)+"ms"+"v="+v); cdlsync.countDown(); } } public class LongAddrThread implements Runnable{ protected String name; private long starttime; public LongAddrThread(long starttime) { this.starttime = starttime; } @Override public void run() { long v= laccount.sum(); while(v<TAEGET_COUNT){//到达目标值前不断循环 laccount.increment(); v=laccount.sum(); } long endTime = System.currentTimeMillis(); System.out.println("LongAddrThread spend:"+(endTime-starttime)+"ms"+"v="+v); cdladdr.countDown(); } } public void testAtomicLong() throws InterruptedException{ ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREADS); long starttime = System.currentTimeMillis(); LongAddrThread atomic = new LongAddrThread(starttime); for(int i=0;i<TASK_COUNT;i++){ executorService.submit(atomic); } cdladdr.await(); executorService.shutdown(); } public void testAtomic() throws InterruptedException{ ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREADS); long starttime = System.currentTimeMillis(); AtomicThread atomic = new AtomicThread(starttime); for(int i=0;i<TASK_COUNT;i++){ executorService.submit(atomic); } cdlatomic.await(); executorService.shutdown(); } public void testSync() throws InterruptedException{ ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREADS); long starttime = System.currentTimeMillis(); SyncThread sync = new SyncThread(starttime,this); for(int i=0;i<TASK_COUNT;i++){ executorService.submit(sync); } cdlsync.await(); executorService.shutdown(); } public static void main(String[] args) throws InterruptedException { LongAdderDemo l1= new LongAdderDemo(); LongAdderDemo l2= new LongAdderDemo(); LongAdderDemo l3= new LongAdderDemo(); l3.testAtomicLong(); l1.testSync(); l2.testAtomic(); }}查的是无锁原子最快,奇怪
解决伪共享
LongAddr的增强版,LongAccumulator
都将一个long型整数进行分割,储存在不同的变量中,防止多线程竞争
LongAddr只是每次对给定的整数执行一次加法,LongAccumulator可以实现任意函数操作
- public LongAccumulator(LongBinaryOperator accumulatorFunction,
- long identity) {
- this.function = accumulatorFunction;
- base = this.identity = identity;
- }
public LongAccumulator(LongBinaryOperator accumulatorFunction, long identity) { this.function = accumulatorFunction; base = this.identity = identity; }第一个参数是需要执行的二元函数(接收俩个long型参数并返回long),第二个参数是初始值
- public class LongAccumulatorDemo {
- //通过多线程访问若干整数,并返回最大值
- public static void main(String[] args) throws InterruptedException {
- LongAccumulator accumulator = new LongAccumulator(Long::max, Long.MIN_VALUE);
- Thread[] ts = new Thread[1000];
- for(int i=0;i<1000;i++){
- ts[i]=new Thread(()->{
- Random random = new Random();
- long value = random.nextLong();
- accumulator.accumulate(value);
- });
- ts[i].start();
- }
- for(int i=0;i<1000;i++){
- ts[i].join();
- }
- System.out.println(accumulator.longValue());
- }
- }
public class LongAccumulatorDemo { //通过多线程访问若干整数,并返回最大值 public static void main(String[] args) throws InterruptedException { LongAccumulator accumulator = new LongAccumulator(Long::max, Long.MIN_VALUE); Thread[] ts = new Thread[1000]; for(int i=0;i<1000;i++){ ts[i]=new Thread(()->{ Random random = new Random(); long value = random.nextLong(); accumulator.accumulate(value); }); ts[i].start(); } for(int i=0;i<1000;i++){ ts[i].join(); } System.out.println(accumulator.longValue()); }}accumulate传入数据,Long::max函数句柄识别最大值并保存在内部(可能是cell数组内,也可能是base),通过longValue()函数对所有的cell进行Long::max操作,得到最大值
- java8与并行
- java8与并行
- Java8系列--并行流与并行流的性能测试
- Java8函数式编程3-并行与并发
- JAVA8新特性[第五季]-并行流与串行流
- java8并行流操作
- Java8---并行流
- java8 并行流使用
- Java8--并行流
- java8实战六:并行流
- java8新特性:Stream多线程并行数据处理
- java8 Lambda 与 Stream
- AndroidStudio与Java8
- Java8新特性——并行流parallelStream
- 在使用java8并行流的时候的一点问题
- java8新特性(六):Stream多线程并行数据处理
- java8 并行编程教程——Threads 和 Executors
- 详解Java8特性之Stream API并行流
- Windows下用命令打开数据库
- 认真学习php面向对象-6
- 路漫漫其修远兮
- Qt4及Qt5的下载、安装和使用
- JavaScript中DOM中节点获取
- java8与并行
- bzoj1008 [HNOI2008]越狱(组合数学+快速幂)
- 第五章 C++与STL入门
- python函数参数
- qt开发环境
- Spring学习系列:错误记录(一):Spring注解错误记录
- APUE之线程创建与终止
- 埃及分数
- Codeforces Round #425 (Div. 2) A