by yushaoyang -2018-03-11
///////////////////////////////////////////集合的线程安全问题/////////////////////////////////////////////////////// @Test public void testName0() throws Exception { Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 }; List<Integer> listOfIntegers = new ArrayList<>(Arrays.asList(intArray)); // for (Integer i : listOfIntegers) { // if (i==2) { // listOfIntegers.remove(Integer.valueOf(2)); // } // } for (int i = 0; i < listOfIntegers.size(); i++) { if (i==1) { listOfIntegers.remove(Integer.valueOf(2)); } } } //对于集合,最好避免有状态的lambda操作 @Test public void testName0_1() throws Exception { Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 }; List<Integer> listOfIntegers = new ArrayList<>(Arrays.asList(intArray)); // listOfIntegers.stream() // .filter(a -> { // if (a == 2) { // listOfIntegers.remove(Integer.valueOf(2)); // } // return true; // }).forEach(System.out::println); // listOfIntegers.stream() // .filter(a -> { // if (a == 2) { // listOfIntegers.add(Integer.valueOf(2)); // } // return true; // }).forEach(System.out::println); //这是可行的 List<Integer> list1 = new ArrayList<>(); long count = IntStream.rangeClosed(1, 1000) .filter(s->list1.add(s)) .count(); System.out.println(list1.size()); } /////////////////////////////////////////parallel的线程安全问题///////////////////////////////////////////// //线程安全问题 forEachOrdered:按照流的顺序遍历,牺牲了效率 @Test public void foreachTest() throws Exception { long s=System.currentTimeMillis(); List<Integer> list1 = new ArrayList<>(); IntStream.rangeClosed(1, 1000_0000) .parallel() .forEach(list1::add); // System.out.println(list1); System.out.println(list1.size()); System.out.println("花费时间:"+(System.currentTimeMillis()-s)); //2475 } //需求:往List添加1000条数据 //如何解决parallel线程安全问题 //推荐:使用collect和reduce接口(可以支持有状态操作),如果不方便,可以使用下面的方法 //1.尽量少用forEach来进行并发时的一些有状态操作,如果你非要用,可以用forEachOrdered代替 //2.如果你就是要用forEach,那么可以使用安全的共享变量 //3.可以在forEach内部加锁 //推荐 @Test public void foreachTest1() throws Exception { long s=System.currentTimeMillis(); List<Integer> collect = IntStream.rangeClosed(1, 1000) .boxed() .parallel() .collect(Collectors.toList()); System.out.println(collect.size()); System.out.println("花费时间:"+(System.currentTimeMillis()-s)); } //方式1:使用forEachOrdered,按流顺序操作,也是并发的,不过比foreach性能低,在数据量很大的时候(比如1000_0000),才能体现他的效率,否则不如安静的用窜行; //即在数据量非常大的情况下:并发foreach<并发forEachOrdered<窜行 @Test public void foreachTest2() throws Exception { long s=System.currentTimeMillis(); List<Integer> list1 = new ArrayList<>(); IntStream.rangeClosed(1, 1000) .parallel() // .forEach(list1::add); .forEachOrdered(list1::add); System.out.println(list1); System.out.println(list1.size()); System.out.println("花费时间:"+(System.currentTimeMillis()-s)); } //方式2:使用安全的共享变量 @Test public void foreachTest3() throws Exception { long s=System.currentTimeMillis(); List<Integer> list1 = Collections.synchronizedList(new ArrayList<>()); IntStream.rangeClosed(1, 1000) .parallel() .forEach(list1::add); System.out.println(list1); System.out.println(list1.size()); System.out.println("花费时间:"+(System.currentTimeMillis()-s)); } //方式3:forEach内部加锁 @Test public void foreachTest4() throws Exception { Lock lock = new ReentrantLock(); long s=System.currentTimeMillis(); List<Integer> list1 = new ArrayList<>(); IntStream.rangeClosed(1, 1000) .parallel() .forEach(cc->{ lock.lock(); list1.add(cc) ; lock.unlock(); }); System.out.println(list1); System.out.println(list1.size()); System.out.println("花费时间:"+(System.currentTimeMillis()-s)); } /////////////////////////////parallel有状态操作/////////////////////////////////////////////////////// //前面说到:有状态操作可能会影响并发 @Test public void testName3() throws Exception { IntStream.generate(()->(int)(Math.random()*100)) .limit(50) .parallel() .sorted() .peek(s->System.out.println(Thread.currentThread().getName())) .forEach(System.out::println); } @Test public void testName4() throws Exception { List<Integer> list = IntStream.generate(()->8) .limit(50) .boxed() .parallel() .peek(s->System.out.println(Thread.currentThread().getName())) .distinct() // .peek(s->System.out.println(Thread.currentThread().getName())) .collect(Collectors.toList()); Collections.sort(list); System.out.println(list); }