掘金阅读记录

1.死锁

    1)死锁的定义:死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

    2)java中查看死锁的工具:① Jstack命令 ②Jconsole工具

    3)预防死锁的措施:①以确定的顺序获得资源 ②超时放弃

    4)其他形式的死锁:①线程池死锁 ②网络连接池死锁

参考链接:https://juejin.im/post/5aaf6ee76fb9a028d3753534


2.sql索引及优化

参考链接1:https://juejin.im/post/5ab0f39df265da23866fba55(优化)

参考链接2:https://juejin.im/post/5a6873fbf265da3e393a97fa(索引)


3.http/2

简介:基于SPDY/2的基础上开发的新版本http协议

    1)优点:比http/1.1及1的版本传输速度高出50%左右,文中举了一个例子,当同时请求379张图片时,HTTP/1.1加载用时4.54s,HTTP/2加载用时1.47s。

    2)变化:①它在应用层和传输层之间加了一个二进制分帧,把来自传输层的数据再分成更小的消息和帧,并采用二进制编码。这种单连接多资源的方式,减小服务器的压力,使得服务器的内存变小,并且由于TCP请求条数的减少,减轻网络传输拥塞,加快慢启动,使得丢包和拥塞恢复得更快。

                  ② 多路复用:多路复用允许同时通过单一的http/2 发送多重的“请求-响应”消息。

                  ③ header压缩:http/1 每次都要携带大量且重复的header信息,http/2用了HPACK算法对header进行了压缩。

                  ④ 服务器推送:简单来讲,就是当服务器和浏览器建立了连接之后,服务器会主动将一些资源推送给客户端并且缓存起来的机制。

参考链接:https://juejin.im/post/5ab6f8f06fb9a028ca52edc2


4.红黑树

1)定义:红黑树是一种自平衡的二叉查找树。

2)特点:节点颜色分为红色和黑色,根节点必为黑色,叶子节点也为黑色(null);一条路径中节点间必须红黑相间,不能够有超过两个的连续红或黑节点;从根节点沿不同路径到达同一个叶子节点经过的黑色节点个数相同;最长路径不超过最短路径的两倍。
3)调整方式:节点变色及旋转。

4)存在意义:弥补传统二叉查找树有可能插入不平衡的情况。

参考链接:https://juejin.im/post/5a27c6946fb9a04509096248

(这篇链接通过图画的方式,很简单易懂,可以对红黑树有一个最基本的了解,但是后面还是要自己多琢磨才能理解)


5.JVM的GC算法

1)垃圾判定算法:引用计数算法、可达性分析算法

    ①引用计数算法:通过判断对象的引用数量来决定是否回收。缺点是两个互相引用的对象无法回收,且很难处理循环引用。

    ②可达性分析算法(根搜索算法):以GC roots为起点,向下搜索,能够搜索到的引用对象即为可达节点,其余的视为不可达节点。根据树的可达性来判断对象是否被回收。如果对象不可达,则为可回收的。

PS:一般来说,对象要被判定为可回收要被标志两次及以上。

2)四种引用

    ①强引用:例如  Object c = new Object(),这样直接new出来的引用对象为强引用,一般不能回收强引用对象。

    ②软引用:指有用但非必需的引用对象。这种引用对象将会在发生内存溢出之前被纳入第二次回收,如果此次回收还未能获得足够空间,则会抛出内存溢出异常。

    ③弱引用:同样指非必需的引用对象。但它比软引用更弱,无论系统当前空间是否充足,只有弱引用关系的引用对象都会被回收。

    ④虚引用:最弱的一种引用。它存在的意义就是在所引用的对象被系统回收时收到通知。

3)JVM的垃圾回收算法:标记-清除算法、复制算法、标记-整理算法、分代搜集算法。

     科普:老年代:指堆中很少垃圾回收的区域。

               新生代:指堆中有大量垃圾回收的区域。

    ①标记-清除算法:定义:最原始的算法,标记可回收对象,然后清除。

                                缺点:效率不高,内存碎片多,不易进行空间分配。

    ②复制算法:定义:把内存空间分为Eden 和 Survivor 两部分,其中suvivor有两个。引用对象都放在Eden和其中一块suvivor中,等到垃圾回收时,把Eden中不可回收对象全部复制到其中的一个suvivor上,清理另外的suvivor和Eden。Eden一般空间分配较大,suvivor较小。 

                        缺点:浪费空间,当不可回收对象多的时候,复制效率会变低;如果出现不可回收对象极端多的情况,并且还要借用老年代的空间。

    ③标记-整理算法:定义:在垃圾回收的时候,把不可回收对象往内存的一端移动,清理边界外的空间。适用于老年代的空间。

                                 缺点:效率不高,不仅要标记不可回收对象,还要整理它们的引用地址,效率上不如复制算法。

                        

    ④分代搜集算法:不能算新算法,它是融合了复制算法和标记整理-算法。就是在新生代中和老年代中使用各自合适的方法。新生代由于有大量新生成的对象,故回收对象多,采用复制算法合适;而老年代采用标记-清除或者标记-整理算法合适。

参考链接:http://www.cnblogs.com/wupeixuan/p/8670341.html


6.JAVA的深拷贝和浅拷贝

    1)JAVA对象类型:基本类型和引用类型

浅拷贝:对于基本类型,即把当前对象的值拷贝;对于引用类型,即把当前对象的引用拷贝。

深拷贝:对于基本类型,即把当前对象的值拷贝;对于引用类型,即创建一个新对象,并按照当前对象的参数和配置来初始化。

    2)clone()方法

对于一个成员变量只有基本类型的对象来说,对它实现clone()方法即为实现深拷贝;对于一个成员变量有引用变量类型的对象来说,对它实现clone()方法即为实现浅拷贝。因为对于类里面的引用变量,clone()方法不会创建一个新对象,而只是单纯地复制这个引用。

    3)实现深拷贝的方法

    ① 序列化和反序列化

    ②自定义clone():在含有引用变量类型的对象中重写clone()方法,使得此引用变量在拷贝的时候也能创建一个新对象。

参考链接:https://juejin.im/post/5ab75dde5188255579189f2d

(这篇文章错别字有点多,而且部分地方好像打错了= =不过还是能看懂的)


7.java并发设计模式--不可变模式

    1)不可变定义:即对象创建之后不能改变,更具体一点,即对象的属性都不变。对原对象的操作都将返回原对象的拷贝。

    2)设计要点:①类的声明为final,防止父类对其修改。

                        ②类的属性声明为private,并将所有setter()方法去掉,防止外界对其进行修改。

                        ③类的属性声明为final,如果为可变对象类型,则要重新new一个对象返回。

   3)注意:当类中的变量类型为可变对象的时候(如Date类型的变量),在类初始化的时候应该重新new一个新的对象返回。

   4)优点和缺点:①优点:由于不可变,所以避免了线程同步的开销;避免了由于修改数据产生的异常。

                             ②缺点:每次都要返回新对象,浪费空间,不易回收。

   5)应用场景:①不适合数据大、创建频繁的对象,数据大且创建频繁的对象容易导致内存泄漏。

                          ②适合于多线程场景中的同步,不适合于线程同步。

                          ③适合表示抽象数据类型(例如数字、枚举、颜色等)的值

(其实应用场景我不太懂第二第三点)

参考链接:https://juejin.im/post/5ac1cbde518825558723b6e9


8.java中的值传递

    1)概念:①形参:即形式参数,是在定义函数名和函数体中使用的参数,目的是用来接收调用该函数时传入的参数。

                    ②实参:即实际参数,在调用有参函数时,主调函数和被调函数之间具有数据传输。实参即为被调函数函数名括号内的参数。

                    ③值传递:传入的是一份实参的拷贝值,在函数内进行操作时不改变实参。

                    ④引用传递:传入的是实参的地址,在函数内进行操作时改变实参。

                    ⑤按共享传递:按共享传递,指的是在函数调用中,传递函数的是实参地址的拷贝。(如果实参在栈中,则直接拷贝实参。)

举个例子:

public static void main(String[] args) {
   ParamTest pt = new ParamTest();
   pt.sout("Hollis");//实际参数为 Hollis
}

public void sout(String name) { //形式参数为 name
   System.out.println(name);
}


    2)值传递与引用传递的根本区别:实参是否有被拷贝,如果有,则为值传递;如果没有,则为引用传递。

    3)java中为什么只有值传递:对于基本对象,拷贝的是值;对于引用对象,拷贝的是对象的引用。两者都是拷贝,而不是传递地址。

    4)总结:无论是按值传递还是引用传递,都是一种求值策略。实际上,java中的传递应该属于按共享传递,按共享传递不过是值传递的一种特例。

参考链接:https://mp.weixin.qq.com/s/F7Niaa7nD1tLApCEGKAj4A


9.1多线程入门

之前一直没有用多线程,最近要写项目的客户通信部分,想着要用到,刚好重温一下(这部分我真的忘得一干二净)

    1)概念:①进程:程序的一个执行过程

                    ②线程:是进程的一部分,它与进程不同的是,多个线程共享一组资源和空间,也成为轻量级进程。

                    ③多线程:几乎同时执行多个线程(几乎是因为,并不是同时执行,而是执行完一个再执行另外一个)

                    ④进程和线程的区别:进程是相互独立的,而线程可能会互相影响。

    2)使用方法:①继承Thread类    ②实现runnable接口

    3)实例变量和线程安全

        ①实例变量:有共享和不共享之分。

        ②线程安全:在方法前实现加上synchronized关键字即可。

    4)常用方法及停止多线程的方法

        参考文章中的方法,停止多线程的方法为:return+interrupt;

    5)线程的优先级别

        级别有1-10,默认为5,数字越大则级别越高。优先级具有继承性。

    6)多线程分类

        ①用户线程:运行在前台,执行具体的任务。

        ②守护线程:运行在后台,为前台线程服务。典型的守护线程有垃圾回收线程。可以通过调用Thead类的setDaemon(true)方法设置当前的线程为守护线程。

参考链接:https://juejin.im/post/5ab116875188255561411b8a


9.2 synchronized关键字

    1)存在意义:为了解决线程安全问题,防止多个线程同时操作统一实例变量。

    2)缺点:如果线程A获得了某对象的锁,且线程A执行任务时间长,则线程B必须等到A执行完才能继续执行。

    2)产生的锁:synchronized产生的锁均为对象锁,即锁定一个对象。如果出现两个或多个线程同时访问同一个对象,则先获得锁的线程优先执行,其他线程等待;如果是访问多个对象,则会产生多个锁,线程之间互不干扰。(之前这里有点困惑) 如果多个线程同时访问同一对象未加synchronized关键字的方法,则会对该方法进行异步调用。只要加上synchronized关键字即可解决。此关键字可解决脏读问题。

    3)synchronized锁可重入

        ①可重入锁:即自己可以再次获取自己的内部锁。如果锁不可重入,则会造成死锁。

        ②具有继承性:子类继承父类,可继承该特性。且出现异常时,会自动释放锁。

    4)同步不具有继承性:如果一个父类带有synchronized关键字的方法,子类继承并重写该方法,该方法不能继承同步,要在该方法前加上synchronized关键字才可以。

参考链接:https://mp.weixin.qq.com/s/_xSYAxOqUrvZ7-L7dUxgGA


9.3 synchronized语句块

    1)存在意义:解决synchronized关键字的缺点。

    2)synchronized(this)同步代码块:当一个线程访问synchronized同步代码块时,此代码块为同步调用;另一个线程仍可访问该对象的非synchronized同步代码块,此代码块为异步调用。并且访问synchronized同步代码块的线程持有该对象的锁。

    3)synchronized(object)代码块间使用:与2类似,如果object为同一个对象监视器,则线程执行同步,否则为异步。

    4)静态同步synchronized方法和synchronized(class)代码块:给当前类上锁。对当前类的所有实例有效。

    5)String具有的常量池属性:String具有常量池缓存的功能,所以尽量避免用synochronized(string)而是用synchronized(object),否则会出现两个线程持有相同的锁,导致只有一个线程能运行的结果。

参考链接:https://mp.weixin.qq.com/s/EIfN8XK-wz5FazxXfXEV3A


10.关于类的对象创建和初始化 

    1)初始化父类:当new一个子类对象时,父类对象不会被隐式创建。而是调用父类的构造函数和实例代码块,完成对继承而来的属性的初始化。

    2)this和super关键字:this为当前实例对象的引用,super为当前实例对象的父类的引用。

    3)完整的初始化过程

        通过面试题来理解:

        面试题一:

public class A {
    static {
        System.out.println("1");
    }
    public A(){
        System.out.println("2");
    }
}
public class B extends A {
    static{
        System.out.println("a");
    }
    public B(){
        System.out.println("b");
    }
}
Main 函数调用:
public static void main(String[] args){
    A ab = new B();
    ab = new B();
}

最终的输出结果为:1 a 2 b 2 b(这里为方便书写,把换行省略了)

分析:①类加载阶段:判断父类A,再判断子类B。发现都没有加载,在类加载的最后阶段,初始化阶段会调用编译器生成的方法,完成类中的所有静态变量赋值,包括静态块的执行。所以会打印出 1 a。

          ②实例初始化阶段:加载完后,开始实例化对象,执行new。实例化分为三个先后顺序阶段,实例属性字段的初始化,实例代码块的执行,构造函数的执行。先父类再子类,于是打印出2 b。

此时,第一条语句已经执行结束了。

然后是第二条语句,由于刚开始类已经加载完了,所以只要实例初始化,所以会打印出2 b。至此,两条语句执行结束。


        面试题二:

public class X {
    Y y = new Y();
    public X(){
        System.out.println("X");
    }
}
public class Y {
    public Y(){
        System.out.println("Y");
    }
}
public class Z extends X {
    Y y  = new Y();
    public Z(){
        System.out.println("Z");
    }
}
Main 函数调用:
public static void main(String[] args){
    new Z();
}

输出的结果为:Y X Y Z。运用以上分析可得到。

参考链接:https://juejin.im/post/5acc72bdf265da23766b9da7


11.关于redis(内容有点点点点多)

    参考链接:https://juejin.im/post/5ad6e4066fb9a028d82c4b66


12.JAVA后端开发规范

看了这篇文章之后,收获很多,无论是在编码规范还是sql相关,我发现很多我都没注意到。

参考链接:https://juejin.im/post/5ada99fff265da0b8a672fbd




                



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值