代码编程要求高内聚低耦合(我(线程)拿遥控器开(操作)空调(高内聚,空调被封装只有一个遥控开关) )
1.线程 操作 资源类
JAVA Lambda表达式函数式接口
1. 复制小括号 写死右箭头 落地大括号(函数式接口中只能有一个方法)
2. @FunctionalInterface
3. default 可以定义多个
4. static 可以是多个
package work; @FunctionalInterface interface Foo{ public int run(); default void abs() { System.out.println("hi"); } default void abc() { System.out.println("hi"); } static void aaa() { System.out.println("in aaa"); } static void bbb() { System.out.println("in bbb"); } } public class FunDemo { public static void main(String[] args) { Foo foo = ()->{ System.out.println("aa"); return 0;}; foo.run(); //函数式接口调用 foo.abs(); //默认的可以有多个 Foo.aaa(); // 静态方法直接类应用, } }
Arraylist:https://www.cnblogs.com/msymm/p/9872818.html
3 ArrayList源码解析
总结:
(01) ArrayList 实际上是通过一个数组去保存数据的。当我们构造ArrayList时;若使用默认构造函数,则ArrayList的默认容量大小是10。
(02) 当ArrayList容量不足以容纳全部元素时,ArrayList会重新设置容量:新的容量=“(原始容量x3)/2 + 1”。:hashmap的初始值是16每次扩容是乘以2:hashset 容器的大小始终是2的幂,默认为16不在赘述
(03) ArrayList的克隆函数,即是将全部元素克隆到一个数组中。
(04) ArrayList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写入“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
Arraylist的是线程不安全会出现并发修改异常:(在大并发中还是使用vector或者CopyOnWriteArrayList:vector在操作的时候是会锁住整个list所以不太好,)
例如:
package work; import java.util.ArrayList; import java.util.List; public class run_test { public static void main(String[] args) { List<String> list = new ArrayList<>(); for (int i = 0; i < 3; i++) { new Thread(()->{ list.add("a"); System.out.println(list);}).start(); } } }
结果:
有时候也会这样:正确的是这样
解决办法: 1. new vector
2. collections.synchornizedlist(new ArrayList<>())
3. copyonwriteArraylist() // 并发时推荐写时复制
set时使用:copyonwriteArraySet()
map时使用:concurrentHashMap
写时复制 copyonwrite 容器即是写时复制的容器,网一个容器添加元素的时候不直接网=往当前容器的object[ ] 添加,二十先将容器Object[ ]进行copy。复制出一个新的容器Object [ ] newElements, 然后往新的Object [ ] newElements里面添加元素,添加完元素之后,在将原容器的应用指向新的容器SetArray(newElements)。这样做的好处是可以copyonwrite容器进行并发的读,而不需要加锁,羊为当前容器不会添加任何元素。所以copyonwrite容器也是一种读写分离的思想,读和写不同的容器。
1. 接口不可以实例化,为什么我们写的接口可以new呢?是因为我们的编译器在编译的时候自动生成了一个program的类(这就是为什么list接口不可以new但是我们自己写的接口却可以new)
HashSet的底层是Hashmap 为什么hashmap可以变成hashset呢,是因为hashmao的k就是我们在set中输入的值,而value则是一个Object类型的 persent的常量(首先数组存储区间是连续的,占用内存严重,故空间复杂度很大,而且插入删除困难,但是hashmap底层运用到了哈希表,它综合了数组和链表的优点,查询、插入删除都相对简单,占用空间也小,所以底层运用hashmap。空对象就是为了凑HashMap的value值的,是一个虚拟值没什么用。)
多线程的编程模板套路:
1.高内聚低耦合前提下,线程操作资源类
2.判断/干活/通知
3. 防止虚假唤醒 //在多个线程并行中判断为了防止错误判断最好用while循环而不是if
package day_one; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.TimeUnit; public class Runner { private int num=0; public synchronized void incry() throws Exception { while (num!=0) { this.wait(); } Thread.sleep(400); num++; System.out.println(Thread.currentThread().getName()+" "+"num is:"+num); this.notifyAll(); } public synchronized void decry() throws Exception { while (num==0) { this.wait(); } Thread.sleep(300); num--; System.out.println(Thread.currentThread().getName()+" "+"num is:"+num); this.notify(); } public static void main(String[] args) { Runner runner = new Runner(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { runner.incry(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace();}}}, "a").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { runner.decry(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace();}}}, "a").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { runner.incry(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace();}}}, "c").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { runner.decry(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace();}}}, "d").start(); } }
a num is:1 d num is:0 c num is:1 a num is:0 c num is:1 a num is:0 c num is:1 a num is:0 c num is:1 a num is:0 c num is:1 a num is:0 c num is:1 a num is:0 c num is:1 a num is:0 c num is:1 a num is:0 c num is:1 a num is:0 c num is:1 a num is:0 a num is:1 d num is:0 a num is:1 d num is:0 a num is:1 d num is:0 a num is:1 d num is:0 a num is:1 d num is:0