Java--JUC--集合的线程安全问题
- 标准的接口:超过一个方法的定义
- 函数是接口:有且仅有一个方法的定义,可以使用@FunctionalInterface,可以自己加上,自己不加在内部也会自动位我们加上这个注解
- lambda表达式形式:拷贝小括号(接口中方法的小括号和里面的参数),写死右箭头,落地大
- 在函数式接口中:
- default 修饰的方法可以有多个,(此方法的具体的实现)
- static类型的方法也可以有多个
- 函数是接口的调用方式:
-
public static void main(String[] args) { // 普通形式 Foo foo=new Foo() { @Override public void sayHello() { System.out.println("sayHello****"); } }; // lambda形式的调用 Foo foo1=()->{ System.out.println("sayHello****"); }; foo.sayHello(); foo1.sayHello(); }
-
- 函数是接口的定义:
-
//标准接口:接口中超过一个方法 //函数式接口:当借口中有且仅有一个方法时,才会使用@FunctionalInterface,可以自己加上,自己不加在内部也会自动位我们加上这个注解 @FunctionalInterface interface Foo{ // 接口有且仅有一个方法 public void sayHello(); // public int add(int x,int y); default void sayHello(int x,int y){ System.out.println(x+y); } default void sayHello1(int x,int y){ System.out.println(x+y); } public static int dey(){ return 0; } public static int dey1(){ return 0; } }
-
- 线程的实现的接口Runnable接口是函数是接口可以使用lambda表达式的形式的调用
-
new Thread(() ->{ for (int i=1;i<=40;i++) { ticket.sale(); } },"A").start(); new Thread(() ->{ for (int i=1;i<=40;i++) { ticket.sale(); } },"B").start(); new Thread(() ->{ for (int i=1;i<=40;i++) { ticket.sale(); } },"C").start();
-
- arraylist创建时的初始值时10,hasmap创建时的初始值时16,第一次扩容扩容到15,拷贝(搬家)的方式:arraylist.copyof()。第二次扩容22,线程不安全
- 解决arraylist线程安全的三种方式:
- List list=new Vector();
- List list= Collections.synchronizedList(new ArrayList<>());
- List<String> list=new CopyOnWriteArrayList<>()
- 写时复制(List<String> list=new CopyOnWriteArrayList<>())
- CopyOnWrite容器即写时复制的容器。往一 - 个容器添加元素的时候,不直接往当前容器object[]添加,而是先将当前容器object[ ]进行copy,
- 复制出- -个新的容器0bject[] newElements, 然后新的容器0bject[] newElements 里添加元素,添加完元素之后,
-
再将原容器的引用指向新的容器setArray(newElements);. 这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一-种读 写分离的思想,读和写不同的容器
-
public boolean add(E e) final ReentrantLock Lock = this. lock; Lock. lock(); try object[] elements = getArray(); . int len = elements. length; object[] newElements = Arrays . copyof(elements, len + 1); newELements[len] = e; setArray(newELements); return true; finally{ lock. unlock(); }
- 解决hashSet线程安全问题:
- hashSet是线程不安全的,他的底层是HashMap,
- HashMap是key -v键值对,但是HashSet是一个值,是如何实现HashSet的呢?key是我们向set传入的值,但是Value是一个Present Object类型的常量,所有我们只用传入key就可以不用传入value
-
Set<String> set=new CopyOnWriteArraySet<>();
- 解决HashMap的线程安全问题
-
Map<String,Object> map=new ConcurrentHashMap<>();
-
- 解决线程安全的具体代码
-
public void mapNotSafe(){ // Map<String,Object> map=new HashMap(); // 解决Map线程安全的问题 Map<String,Object> map=new ConcurrentHashMap<>(); for (int i=0;i<30;i++){ new Thread(() ->{ map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8)); System.out.println(map); },String.valueOf(i)).start(); } } public void setNotSafe() { // Set<String > set =new HashSet<>(); // 解决set线程安全问题,读写分离的原理,读写使用不同的容器 Set<String> set=new CopyOnWriteArraySet<>(); for (int i = 0; i < 30; i++) { new Thread(() -> { set.add(UUID.randomUUID().toString().substring(0, 8)); // set.forEach(System.out::println); System.out.println(set); }, String.valueOf(i)).start(); } } public void listNotSafe() { // List list=new ArrayList(); // List list=new Vector(); // List list= Collections.synchronizedList(new ArrayList<>()); List<String> list = new CopyOnWriteArrayList<>();//写时复制,读写分离的原理 // 写的时候会复制一份,然后在新的容器中写,不会影响其他人的读 for (int i = 0; i < 30; i++) { new Thread(() -> { list.add(UUID.randomUUID().toString().substring(0, 8)); System.out.println(list); // list.forEach(System.out::println); }, String.valueOf(i)).start(); } }
-
-