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);
}