java8与并行

来源:互联网 发布:mac恢复出厂系统版本 编辑:程序博客网 时间:2024/06/07 03:09

申明式的编程方式

不需要提供明确的指令操作,所有的细节指令被程序库封装,只要提出要求,申明用意

[java] view plain copy
print?
  1. public class Test1 {  
  2.     public static void main(String[] args) {  
  3.         int[]ary={1,2,5,2};  
  4.         for (int i = 0; i < ary.length; i++) {  
  5.             System.out.println(ary[i]);  
  6.         }  
  7.         Arrays.stream(ary).forEach(System.out::println);  
  8.     }  
  9. }  
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);    }}
不变的对象
几乎所有传递的对象都不会被轻易修改

[java] view plain copy
print?
  1. public class Test1 {  
  2.     public static void main(String[] args) {  
  3.         int[]ary={1,2,5,2};  
  4.         Arrays.stream(ary).map((x)->x=x+1).forEach(System.out::println);  
  5.         Arrays.stream(ary).forEach(System.out::println);  
  6.     }  
  7. }  
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

[java] view plain copy
print?
  1. public class Test1 {  
  2.     static int[]arr={1,2,3,45,6};  
  3.     public static void main(String[] args) {  
  4.         for(int i=0;i<arr.length;i++){  
  5.             if(arr[i]%2!=0){  
  6.                 arr[i]++;  
  7.             }  
  8.             System.out.println(arr[i]);  
  9.         }  
  10.         Arrays.stream(arr).map(x->(x%2==0?x:x+1)).forEach(System.out::println);  
  11.     }  
  12. }  
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注释
函数式接口,只定义了单一抽象方法的接口

[java] view plain copy
print?
  1. @FunctionalInterface  
  2. public static interface IntHandler{  
  3.     void handle(int i);  
  4. }  
   @FunctionalInterface    public static interface IntHandler{        void handle(int i);    }
表明它是函数式接口,只包含一个抽象方法,但可以有其他方法,被Object实现的方法都不是抽象方法
接口默认方法

java8可以包含实例方法,需要用default关键字

[java] view plain copy
print?
  1. @FunctionalInterface  
  2. public static interface IntHandler{  
  3.     void handle(int i);  
  4.     default void run(){}  
  5. }  
   @FunctionalInterface    public static interface IntHandler{        void handle(int i);        default void run(){}    }
可以多实现,但会有多继承相同的问题
俩接口有相同实例方法,子类就会报错,需要指定

[java] view plain copy
print?
  1. public interface IHorse {  
  2.     void eat();  
  3.     default void run(){  
  4.         System.out.println(”hourse run”);  
  5.     }  
  6. }  
  7. public interface IAbimal {  
  8.     void eat();  
  9.     default void breath(){  
  10.         System.out.println(”breath”);  
  11.     }  
  12.     default void run(){  
  13.         System.out.println(”abimal run”);  
  14.     }  
  15. }  
  16. public class Mule implements IHorse,IAbimal{  
  17.     @Override  
  18.     public void eat() {  
  19.         System.out.println(”mule eat”);  
  20.     }  
  21.     //重新实现run方法,指定  
  22.     @Override  
  23.     public void run() {  
  24.         IAbimal.super.run();  
  25.     }  
  26.     public static void main(String[] args) {  
  27.         Mule m = new Mule();  
  28.         m.eat();  
  29.         m.run();  
  30.         m.breath();  
  31.     }  
  32. }  
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方法,用于多个比较器的整合
[java] view plain copy
print?
  1. default Comparator<T> thenComparing(Comparator<? super T> other) {  
  2.     Objects.requireNonNull(other);  
  3.     return (Comparator<T> & Serializable) (c1, c2) -> {  
  4.         int res = compare(c1, c2);  
  5.         return (res != 0) ? res : other.compare(c1, c2);  
  6.     };  
  7. }  
    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);        };    }
先比较字符串长度,在按照大小写不敏感的字母顺序排列
[java] view plain copy
print?
  1. 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表达式
即匿名表达式,是一段没有函数名的函数体,可以作为参数直接传递给相关的调用者

[java] view plain copy
print?
  1. List<Integer> numbers = Arrays.asList(1,2,3,4,5);  
  2. 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,不加也会默认

[java] view plain copy
print?
  1. final int num =2;  
  2. Function<Integer, Integer>stringConverter = (from)->from*num;  
  3. 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

[java] view plain copy
print?
  1. public class InstanceMethodRef {  
  2.     static class User{  
  3.         int i;  
  4.         String string;  
  5.         public User(int i, String string) {  
  6.             this.i=i;  
  7.             this.string=string;  
  8.         }  
  9.         public int getI() {  
  10.             return i;  
  11.         }  
  12.         public void setI(int i) {  
  13.             this.i = i;  
  14.         }  
  15.         public String getString() {  
  16.             return string;  
  17.         }  
  18.         public void setString(String string) {  
  19.             this.string = string;  
  20.         }         
  21.     }  
  22.     public static void main(String[] args) {  
  23.         List<User> users = new ArrayList<>();  
  24.         for(int i=1;i<10;i++){  
  25.             users.add(new User(i,“billy”+Integer.toString(i)));  
  26.         }  
  27.         users.stream().map(User::getString).forEach(System.out::println);  
  28.     }  
  29. }  
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)

方法引用也可以直接调用构造函数

[java] view plain copy
print?
  1. static class ConstrMethodRef{  
  2.     @FunctionalInterface  
  3.     interface UserFactory<U extends User>{  
  4.         U create(int id,String name);  
  5.     }  
  6.     static UserFactory<User> uf = User::new;  
  7. }  
  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的实际构造函数进行

函数式编程

[java] view plain copy
print?
  1. public class Test2 {  
  2.     static int[]arr={1,2,3,45,6};  
  3.     public static void main(String[] args) {  
  4.         for (int i : arr) {  
  5.             System.out.println(i);  
  6.         }  
  7.         Arrays.stream(arr).forEach(new IntConsumer() {  
  8.             @Override  
  9.             public void accept(int value) {  
  10.                 System.out.println(value);  
  11.             }  
  12.         });  
  13.           
  14.     }  
  15. }  
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的参数是可以从上下文中推导的,以下不再手动推导,省略接口名

[java] view plain copy
print?
  1. Arrays.stream(arr).forEach((final int x)->{System.out.println(x);});  
        Arrays.stream(arr).forEach((final int x)->{System.out.println(x);});
参数类型也可以推导

[java] view plain copy
print?
  1. Arrays.stream(arr).forEach((x)->{System.out.println(x);});  
Arrays.stream(arr).forEach((x)->{System.out.println(x);});
去除花括号

[java] view plain copy
print?
  1. Arrays.stream(arr).forEach((x)->System.out.println(x));  
Arrays.stream(arr).forEach((x)->System.out.println(x));
lambda表达式,由->分割,左面表示参数,右面实现体
方法引用

[java] view plain copy
print?
  1. Arrays.stream(arr).forEach(System.out::println);  
Arrays.stream(arr).forEach(System.out::println);
lambda表达式不仅可以简化匿名内部类的编写,还可以使用流式api对各种组件进行更自由的装配

输出俩次元素

[java] view plain copy
print?
  1. IntConsumer outprintln = System.out::println;  
  2. IntConsumer errprintln = System.err::println;  
  3. Arrays.stream(arr).forEach(outprintln.andThen(errprintln));  
     IntConsumer outprintln = System.out::println;        IntConsumer errprintln = System.err::println;        Arrays.stream(arr).forEach(outprintln.andThen(errprintln));
使用并行流过滤数据
[java] view plain copy
print?
  1. public class PrimeUtil {  
  2.     public static boolean isPrime(int number){  
  3.         int tmp = number;  
  4.         if(tmp<2){  
  5.             return false;  
  6.         }  
  7.         for(int i=2;i<tmp;i++){  
  8.             if(tmp%i==0){  
  9.                 return false;  
  10.             }  
  11.         }  
  12.         return true;  
  13.     }   
  14.     public static void main(String[] args) {  
  15.         //串行,首先生成1到1000000的数字流,接着使用过滤函数,只选择所有的质数,最后统计数量  
  16.         //IntStream.range(1, 1000000).filter(PrimeUtil::isPrime).count();  
  17.         //并行  
  18.         IntStream.range(11000000).parallel().filter(PrimeUtil::isPrime).count();  
  19.     }  
  20. }  
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();    }}
从集合中得到并行流
[java] view plain copy
print?
  1. //使用stream得到一个流  
  2. double ave = ss.stream().mapToInt(s->s.score).average().getAsDouble();  
  3. //并行化  
  4. 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()串行排序
并行排序

[java] view plain copy
print?
  1. int[] arrr = new int[10000];  
  2. Arrays.parallelSort(arrr);  
      int[] arrr = new int[10000];        Arrays.parallelSort(arrr);
赋值
[java] view plain copy
print?
  1. Random r = new Random();  
  2. //串行  
  3. Arrays.setAll(arr, (i)->r.nextInt());  
  4. //并行  
  5. Arrays.parallelSetAll(arr, (i)->r.nextInt());  
       Random r = new Random();        //串行        Arrays.setAll(arr, (i)->r.nextInt());        //并行        Arrays.parallelSetAll(arr, (i)->r.nextInt());
CompletableFuture
可以作为函数调用的契约,向它请求一个数据,数据没准备好,请求线程会等待,这里可以手动设置完成状态

[java] view plain copy
print?
  1. public class CompletableFutureTest {  
  2.   
  3.     static class AskThread implements Runnable{  
  4.         CompletableFuture<Integer> re = null;  
  5.   
  6.         public AskThread(CompletableFuture<Integer> re) {  
  7.             this.re = re;  
  8.         }  
  9.   
  10.         @Override  
  11.         public void run() {  
  12.             int myRe = 0;  
  13.             try {  
  14.                 myRe = re.get()*re.get();  
  15.             } catch (InterruptedException e) {  
  16.                 e.printStackTrace();  
  17.             } catch (ExecutionException e) {  
  18.                 e.printStackTrace();  
  19.             }  
  20.             System.out.println(myRe);  
  21.         }  
  22.         public static void main(String[] args) throws InterruptedException {  
  23.             final CompletableFuture<Integer> future = new CompletableFuture<>();  
  24.             new Thread(new AskThread(future)).start();  
  25.             Thread.sleep(1000);  
  26.             future.complete(60);  
  27.         }  
  28.     }  
  29. }  
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);        }    }}
异步执行任务
[java] view plain copy
print?
  1. public class CompletableFutureSync {  
  2.   
  3.     public static Integer calc(Integer para){  
  4.         try {  
  5.             Thread.sleep(1000);  
  6.         } catch (InterruptedException e) {  
  7.             e.printStackTrace();  
  8.         }  
  9.         return para*para;  
  10.     }  
  11.     public static void main(String[] args) throws InterruptedException, ExecutionException {  
  12.         final CompletableFuture<Integer> future = CompletableFuture.supplyAsync(()->calc(50));  
  13.         System.out.println(future.get());  
  14.     }  
  15. }  
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()用于没有返回值的场景

都可以指定线程池,也可以用默认线程池,但主线程退出,立即退出系统

流式调用

[java] view plain copy
print?
  1. public class CompletableFutureSync {  
  2.     public static Integer calc(Integer para){  
  3.         try {  
  4.             Thread.sleep(1000);  
  5.         } catch (InterruptedException e) {  
  6.             e.printStackTrace();  
  7.         }  
  8.         return para*para;  
  9.     }  
  10.     public static void main(String[] args) throws InterruptedException, ExecutionException {  
  11.         final CompletableFuture<Void> future = CompletableFuture.supplyAsync(()->calc(50))  
  12.                 .thenApply((i)->Integer.toString(i)).thenApply((src)->”\”“+src+“\”“).thenAccept(System.out::println);       
  13.         future.get();  
  14.     }  
  15. }  
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()方法目的是等待函数执行完成,不使用,因为是异步的,主线程会退出,然后其他线程也会退出,导致方法无法正常执行

异常处理

[java] view plain copy
print?
  1. public class CompletableFutureSync {  
  2.     public static Integer calc(Integer para){  
  3.         try {  
  4.             Thread.sleep(1000);  
  5.         } catch (InterruptedException e) {  
  6.             e.printStackTrace();  
  7.         }  
  8.         return para*para;  
  9.     }  
  10.     public static void main(String[] args) throws InterruptedException, ExecutionException {  
  11.         CompletableFuture<Void> future = CompletableFuture.supplyAsync(()->calc(50))  
  12.                 .exceptionally(ex->{  
  13.                     System.out.println(ex.toString());  
  14.                     return 0;  
  15.                 })  
  16.                 .thenApply((i)->Integer.toString(i)).thenApply((src)->”\”“+src+“\”“).thenAccept(System.out::println);       
  17.         future.get();  
  18.     }  
  19. }  
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

[java] view plain copy
print?
  1. public <U> CompletableFuture<U> thenCompose(  
  2.     Function<? super T, ? extends CompletionStage<U>> fn) {  
  3.     return uniComposeStage(null, fn);  
  4. }  
    public <U> CompletableFuture<U> thenCompose(        Function<? super T, ? extends CompletionStage<U>> fn) {        return uniComposeStage(null, fn);    }
一种是使用thenCompose将执行结果传给下一个CompletableFuture

[java] view plain copy
print?
  1. public class CompletableFutureSync {  
  2.     public static Integer calc(Integer para){  
  3.         try {  
  4.             Thread.sleep(1000);  
  5.         } catch (InterruptedException e) {  
  6.             e.printStackTrace();  
  7.         }  
  8.         return para*para;  
  9.     }  
  10.     public static void main(String[] args) throws InterruptedException, ExecutionException {  
  11.         CompletableFuture<Void> future = CompletableFuture.supplyAsync(()->calc(50))  
  12.                 .thenCompose((i)->CompletableFuture.supplyAsync(()->calc(i)))  
  13.                 .thenApply((src)->”\”“+src+“\”“).thenAccept(System.out::println);          
  14.         future.get();  
  15.     }  
  16. }  
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

[java] view plain copy
print?
  1. public <U,V> CompletableFuture<V> thenCombine(  
  2.     CompletionStage<? extends U> other,  
  3.     BiFunction<? super T,? super U,? extends V> fn) {  
  4.     return biApplyStage(null, other, fn);  
  5. }  
    public <U,V> CompletableFuture<V> thenCombine(        CompletionStage<? extends U> other,        BiFunction<? super T,? super U,? extends V> fn) {        return biApplyStage(null, other, fn);    }
把俩个结果累加

[java] view plain copy
print?
  1. public class CompletableFutureSync {  
  2.     public static Integer calc(Integer para){  
  3.         try {  
  4.             Thread.sleep(1000);  
  5.         } catch (InterruptedException e) {  
  6.             e.printStackTrace();  
  7.         }  
  8.         return para*para;  
  9.     }  
  10.     public static void main(String[] args) throws InterruptedException, ExecutionException {  
  11.         CompletableFuture<Integer> future1= CompletableFuture.supplyAsync(()->calc(50));  
  12.         CompletableFuture<Integer> future2= CompletableFuture.supplyAsync(()->calc(25));  
  13.         CompletableFuture<Void> future3=future1.thenCombine(future2, (i,j)->(i+j))  
  14.                 .thenApply((src)->”\”“+src+“\”“).thenAccept(System.out::println);          
  15.         future3.get();  
  16.     }  
  17. }  
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提供了乐观的读策略,类似无锁操作

[java] view plain copy
print?
  1. public class Point {  
  2.     private double x,y;  
  3.     private final StampedLock s1 = new StampedLock();  
  4.     void move(double deltax,double deltay){//排他锁  
  5.         long stamp = s1.writeLock();  
  6.         try {  
  7.             x+=deltax;  
  8.             y+=deltay;  
  9.         } finally{  
  10.             s1.unlockWrite(stamp);  
  11.         }  
  12.     }  
  13.     double distanceFromOrigin(){//只读方法  
  14.         long stamp = s1.tryOptimisticRead();//尝试一次乐观锁,返回一个类似时间戳的邮戳整数  
  15.         double currentx =x,currenty=y;  
  16.         if(!s1.validate(stamp)){//判断是否被修改过  
  17.             stamp = s1.readLock();  
  18.             try {  
  19.                 currentx=x;  
  20.                 currenty=y;  
  21.             } finally{  
  22.                 s1.unlockRead(stamp);  
  23.             }  
  24.         }  
  25.         return Math.sqrt(currentx*currentx+currenty+currenty);  
  26.     }  
  27. }  
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的情况

[java] view plain copy
print?
  1. public class StampedLockCPUDemo {  
  2.   
  3.     static Thread[]holdCpuThreads = new Thread[3];  
  4.     static final StampedLock lock = new StampedLock();  
  5.     public static void main(String[] args) throws InterruptedException {  
  6.         new Thread(){  
  7.             @Override  
  8.             public void run(){  
  9.                 long readLong = lock.writeLock();  
  10.                 LockSupport.parkNanos(600000000000000L);  
  11.                 lock.unlockWrite(readLong);  
  12.             }  
  13.         }.start();  
  14.         Thread.sleep(100);  
  15.         for(int i=0;i<3;i++){  
  16.             holdCpuThreads[i]=new Thread(new HoldCPUReadThread());  
  17.             holdCpuThreads[i].start();  
  18.         }  
  19.         Thread.sleep(10000);  
  20.         //线程中断会占用CPU  
  21.         for(int i=0;i<3;i++){  
  22.             holdCpuThreads[i].interrupt();  
  23.         }  
  24.     }  
  25.     private static class HoldCPUReadThread implements Runnable{  
  26.         @Override  
  27.         public void run(){  
  28.             long lockr = lock.readLock();  
  29.             System.out.println(Thread.currentThread().getName()+”获取读锁”);  
  30.             lock.unlockRead(lockr);  
  31.         }  
  32.     }  
  33. }  
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),用于判断当前线程是否已经释放锁,当一个线程试图获得锁时,取得当前等待队列的尾部节点作为其前序节点,使用如下代码判断前序节点是否已经成功释放锁

[java] view plain copy
print?
  1. while (pred.locked){}  
while (pred.locked){}

[java] view plain copy
print?
  1. /** Wait nodes */  
  2. static final class WNode {  
  3.     volatile WNode prev;  
  4.     volatile WNode next;  
  5.     volatile WNode cowait;    // 读节点列表  
  6.     volatile Thread thread;   // 当可能被暂停时非空  
  7.     volatile int status;      // 0, WAITING, or CANCELLED  
  8.     final int mode;           // RMODE or WMODE  
  9.     WNode(int m, WNode p) { mode = m; prev = p; }  
  10. }  
  11.   
  12. /** Head of CLH queue */  
  13. private transient volatile WNode whead;  
  14. /** Tail (last) of CLH queue */  
  15. 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表示一个等待线程,
[java] view plain copy
print?
  1. private transient volatile long state;//当前锁的等待状态  
private transient volatile long state;//当前锁的等待状态
倒数第八位表示写锁状态,该位为1,表示当前由写锁占用

乐观锁会执行如下操作

[java] view plain copy
print?
  1. public long tryOptimisticRead() {  
  2.     long s;  
  3.     return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;  
  4. }  
    public long tryOptimisticRead() {        long s;        return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;    }
WBIT表示写锁状态位,值为0x80,成功,返回当前值,末尾7位清0,末尾7位表示当前正在读取的线程数量
乐观锁读后有线程申请写锁,state状态改变,设置写锁位为1,通过加上WBIT
[java] view plain copy
print?
  1. public long writeLock() {  
  2.     long s, next;  // bypass acquireWrite in fully unlocked case only  
  3.     return ((((s = state) & ABITS) == 0L &&  
  4.              U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?  
  5.             next : acquireWrite(false, 0L));  
  6. }  
    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,不一致,乐观锁失败

[java] view plain copy
print?
  1. public boolean validate(long stamp) {  
  2.     U.loadFence();  
  3.     return (stamp & SBITS) == (state & SBITS);  
  4. }  
    public boolean validate(long stamp) {        U.loadFence();        return (stamp & SBITS) == (state & SBITS);    }
悲观读锁

[java] view plain copy
print?
  1. public long readLock() {  
  2.     long s = state, next;  // bypass acquireRead on common uncontended case  
  3.     return ((whead == wtail && (s & ABITS) < RFULL &&  
  4.              U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?  
  5.             next : acquireRead(false, 0L));  
  6. }  
    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,释放锁与加锁相反

[java] view plain copy
print?
  1. public void unlockWrite(long stamp) {  
  2.     WNode h;  
  3.     if (state != stamp || (stamp & WBIT) == 0L)  
  4.         throw new IllegalMonitorStateException();  
  5.     state = (stamp += WBIT) == 0L ? ORIGIN : stamp;  
  6.     if ((h = whead) != null && h.status != 0)  
  7.         release(h);  
  8. }  
    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翻倍,减少冲突

[java] view plain copy
print?
  1. public void increment() {  
  2.     add(1L);  
  3. }  
  4. public void add(long x) {  
  5.     Cell[] as; long b, v; int m; Cell a;  
  6.     if ((as = cells) != null || !casBase(b = base, b + x)) {  
  7.         boolean uncontended = true;  
  8.         if (as == null || (m = as.length - 1) < 0 ||  
  9.             (a = as[getProbe() & m]) == null ||  
  10.             !(uncontended = a.cas(v = a.value, v + x)))  
  11.             longAccumulate(x, null, uncontended);  
  12.     }  
  13. }  
    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
[java] view plain copy
print?
  1. public  class LongAdderDemo {  
  2.   
  3.     private static final int MAX_THREADS=3;//线程数  
  4.     private static final int TASK_COUNT=3;//任务数  
  5.     private static final int TAEGET_COUNT=10000000;//目标总数  
  6.       
  7.     private AtomicLong account = new AtomicLong(0L);//无锁的原子操作  
  8.     private LongAdder laccount = new LongAdder();//改进的无锁的原子操作  
  9.     private long count =0;  
  10.     static CountDownLatch cdlsync = new CountDownLatch(TASK_COUNT);  
  11.     static CountDownLatch cdlatomic = new CountDownLatch(TASK_COUNT);  
  12.     static CountDownLatch cdladdr = new CountDownLatch(TASK_COUNT);  
  13.   
  14.     protected synchronized long inc(){//有锁的原子加法  
  15.         return count++;  
  16.     }  
  17.     protected synchronized long getCount(){//有锁的操作  
  18.         return count;  
  19.     }  
  20.     //有锁  
  21.     public class SyncThread implements Runnable{  
  22.         protected String name;  
  23.         private long starttime;  
  24.         LongAdderDemo out;    
  25.         public SyncThread(long starttime, LongAdderDemo out) {  
  26.             this.starttime = starttime;  
  27.             this.out = out;  
  28.         }  
  29.         @Override  
  30.         public void run() {  
  31.             long v= out.getCount();  
  32.             while(v<TAEGET_COUNT){//到达目标值前不断循环  
  33.                 v=out.inc();  
  34.             }  
  35.             long endTime = System.currentTimeMillis();  
  36.             System.out.println(”SynchThread spend:”+(endTime-starttime)+“ms”+“v=”+v);  
  37.             cdlsync.countDown();  
  38.         }  
  39.     }  
  40.     //无锁  
  41.     public class AtomicThread implements Runnable{  
  42.         protected String name;  
  43.         private long starttime;  
  44.         public AtomicThread(long starttime) {  
  45.             this.starttime = starttime;  
  46.         }  
  47.         @Override  
  48.         public void run() {  
  49.             long v= account.get();  
  50.             while(v<TAEGET_COUNT){//到达目标值前不断循环  
  51.                 v=account.incrementAndGet();//无锁的加法  
  52.             }  
  53.             long endTime = System.currentTimeMillis();  
  54.             System.out.println(”AtomicThread spend:”+(endTime-starttime)+“ms”+“v=”+v);  
  55.             cdlsync.countDown();  
  56.         }  
  57.     }  
  58.     public class LongAddrThread implements Runnable{  
  59.         protected String name;  
  60.         private long starttime;  
  61.         public LongAddrThread(long starttime) {  
  62.             this.starttime = starttime;  
  63.         }  
  64.         @Override  
  65.         public void run() {  
  66.             long v= laccount.sum();  
  67.             while(v<TAEGET_COUNT){//到达目标值前不断循环  
  68.                 laccount.increment();  
  69.                 v=laccount.sum();  
  70.             }  
  71.             long endTime = System.currentTimeMillis();  
  72.             System.out.println(”LongAddrThread spend:”+(endTime-starttime)+“ms”+“v=”+v);  
  73.             cdladdr.countDown();  
  74.         }  
  75.     }  
  76.     public void testAtomicLong() throws InterruptedException{  
  77.         ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREADS);  
  78.         long starttime = System.currentTimeMillis();  
  79.         LongAddrThread atomic = new LongAddrThread(starttime);  
  80.         for(int i=0;i<TASK_COUNT;i++){  
  81.             executorService.submit(atomic);  
  82.         }  
  83.         cdladdr.await();  
  84.         executorService.shutdown();  
  85.     }  
  86.     public void testAtomic() throws InterruptedException{  
  87.         ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREADS);  
  88.         long starttime = System.currentTimeMillis();  
  89.         AtomicThread atomic = new AtomicThread(starttime);  
  90.         for(int i=0;i<TASK_COUNT;i++){  
  91.             executorService.submit(atomic);  
  92.         }  
  93.         cdlatomic.await();  
  94.         executorService.shutdown();  
  95.     }  
  96.     public void testSync() throws InterruptedException{  
  97.         ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREADS);  
  98.         long starttime = System.currentTimeMillis();  
  99.         SyncThread sync = new SyncThread(starttime,this);  
  100.         for(int i=0;i<TASK_COUNT;i++){  
  101.             executorService.submit(sync);  
  102.         }  
  103.         cdlsync.await();  
  104.         executorService.shutdown();  
  105.     }  
  106.     public static void main(String[] args) throws InterruptedException {  
  107.         LongAdderDemo l1= new LongAdderDemo();  
  108.         LongAdderDemo l2= new LongAdderDemo();  
  109.         LongAdderDemo l3= new LongAdderDemo();  
  110.         l3.testAtomicLong();  
  111.         l1.testSync();  
  112.         l2.testAtomic();      
  113.     }  
  114. }  
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可以实现任意函数操作

[java] view plain copy
print?
  1. public LongAccumulator(LongBinaryOperator accumulatorFunction,  
  2.                        long identity) {  
  3.     this.function = accumulatorFunction;  
  4.     base = this.identity = identity;  
  5. }  
    public LongAccumulator(LongBinaryOperator accumulatorFunction,                           long identity) {        this.function = accumulatorFunction;        base = this.identity = identity;    }
第一个参数是需要执行的二元函数(接收俩个long型参数并返回long),第二个参数是初始值
[java] view plain copy
print?
  1. public class LongAccumulatorDemo {  
  2.     //通过多线程访问若干整数,并返回最大值  
  3.     public static void main(String[] args) throws InterruptedException {  
  4.         LongAccumulator accumulator = new LongAccumulator(Long::max, Long.MIN_VALUE);  
  5.         Thread[] ts = new Thread[1000];  
  6.         for(int i=0;i<1000;i++){  
  7.             ts[i]=new Thread(()->{  
  8.                 Random random = new Random();  
  9.                 long value = random.nextLong();  
  10.                 accumulator.accumulate(value);  
  11.             });  
  12.             ts[i].start();  
  13.         }  
  14.         for(int i=0;i<1000;i++){  
  15.             ts[i].join();  
  16.         }  
  17.         System.out.println(accumulator.longValue());  
  18.     }  
  19. }  
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操作,得到最大值

原创粉丝点击