零碎笔记(一)

本文深入探讨了TCP协议的工作机制,包括数据发送与确认过程、窗口大小调整等内容。此外,还详细介绍了Java中的线程安全、异常处理、资源管理等高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       TCP的发送缓冲区中的数据,如果收不到接收方的ACK就不会删除,导致发送缓冲区溢出。如果接收方的缓冲区满了,收到数据后会不会向发送方发ACK呢?
       答案:
       1. 只要收到了包,就会ACK。
       2. TCP在ACK的同时会带有window大小值,表示这边能接受的数据量。发送方会根据这个调整数据量。
       3. 接收方缓冲区满时,回给发送方的window值就是0。
       4. 发送方看到window为0的包,会启动一个定时器,隔一段时间发一个包试探。
       5. 一旦接收方缓冲区有足够空间了,就会给window赋上非0值。发送方就又开始发送了。 


       程序中的所有线程共享一个方法区,所以访问方法区信息的方法必须是线程安全的。如果有两个线程都去加载一个叫Lava的类,那只能由一个线程被容许去加载这个类,另一个必须等待。


       wait()等待对象锁和synchronized等待对象锁的区别,wait()等待时,线程是在阻塞状态,所以需要notify或者notifyAll唤醒使线程状态变为就绪状态才能继续竞争对象锁, 而synchronized等待时, 线程本身就在就绪状态, 所以线程可以直接竞争对象锁(线程可能一直在循环查询对象锁是否可用)。还有一点,线程是获取了锁之后才能调用wait(),从而释放锁并阻塞;不能凭空调用wait()。


       一般情况下,对于基本类型用==,对于引用类型用equals()。对于引用类型如果可以用==代替equals(),可以大大提高效率。
       举例:如何判断一个Class是否指定的类型?如果不用instanceof该怎么处理呢?给定一个Class c,判断是否为String类的Class。
            方法1:boolean b=c.getName().equals(String.class.getName());
            方法2:boolean b=(c==String.class);
       第二种方法至少快100倍,甚至1000倍或者10000倍,因为用==几乎不用时间。对于可以使用==的比较,不要使用equals();一般单例类的实例可以使用==,比如枚举类。


try中抛出异常,但如果finally 中也抛出异常的话,try中的异常信息会被忽略掉。例如:
1.异常信息丢失案例
public void test_1(){
    //异常信息丢失案例
    try {
        Integer.parseInt("hello");
    } catch (NumberFormatException e) {
        log.info("{excetion:}",e);
        throw  e; //这个异常被下面的掩盖了。
    }finally{
        int a = 12 / 0; //expected=ArithmeticException.class 这里的异常
    }
}
上面的测试抛出的异常不是try中的NumberFormatException,而是finally 中的ArithmeticException。即try中的异常信息被丢弃。

2. 解决方法之一:
public void test_2(){
    //异常信息丢失案例:解决方法
    try {
        Integer.parseInt("hello");
    } catch (NumberFormatException e) {
        log.info("{excetion:}",e);
        throw e; //这个异常被下面的掩盖了。
    }finally{
        try {
            int a = 12 / 0;
        } catch (Exception e) {
            // 忽略此处异常,上面的主要根源异常就可以跑出去了
        }
    }
}
代码抛出的异常是NumberFormatException,就是try中异常是根源,finally中的异常就丢弃了。

3.解决方法之二:
public void test_3(){
    RuntimeException throwable = null;  
    try {  
        Integer.parseInt("hello");  
    } catch (NumberFormatException e) {  
         throwable = e;  
    } finally {  
           try {  
               int a = 10 / 0;  
           } catch (ArithmeticException e) {  
                if (throwable == null) {  
                       throwable = e;  
                } else {  
                       throwable.addSuppressed(e);  
                }  
           }  
    }  
    if (throwable != null) {  
         log.error("", throwable);  
         throw throwable;  
    }  
}
利用addSuppressed 方法,把异常堆栈信息保留起来,然后再带出去。


       早在Java5.x的时候,Java API为开发人员提供了一个Closeable接口。该接口中包含一个close()方法,允许所有可回收资源的类型对其进行重写实现。7.x版本中几乎所有的资源类型都实现了Closeable接口,并重写了close()方法。也就是说所有可回收的系统资源,将再不必每次使用完后调用close()方法进行资源回收,这一切全部交接给自动资源管理器去做即可。
       例如Reader资源类型继承Closeable接口实现资源自动管理:
   public abstract class Reader implements Readable, Closeable
       当然如果需要在程序中使用自动资源管理,还需要使用API提供的新语法支持,这类语法包含在try语句块内部。7.x确实允许try使用表达式的语法方式实现自动资源管理,但仅限于资源类型。
       使用try表达式实现自动资源管理:
    try(BufferedReader reader = new BufferedReader(new FileReader("路径"));) {
        //...  
    } catch(Exception e) {
        e.printStackTrace();
    }


       声明二进制,早在Java7.x版本之前,开发人员只能够定义十进制、八进制、十六进制等字面值。但是现在完全可以使用“0b”字符为前缀定义二进制字面值。
       定义二进制字面值: int test = 0b010101;   
       需要提示的是,虽然可以直接在程序中定义二进制字面值。但是在程序运算时,仍然会将其转换成十进制展开运算和输出。


在Java中,使用反射的方法加载类的具体代码是:
Class<?> cls = Class.forName("package.ClassName");
但是,如果需要加载的是一个内部类的话,如果使用这种加载方式,会抛出异常:
// 如果使用这样的代码,会抛出ClassNotFoundException
Class<?> cls = Class.forName("package.ClassName.InnerClass");
对于内部类,需要像下面这样写代码:
Class<?> cls = Class.forName("package.ClassName$InnerClass");


非spring管理的类实例如何托管给spring容器管理 
    public void test_contextBeanRegistrationOfExistingObjects() {  
        ApplicationContextBeanRegistrationOfExistingObjects bean = null;  
        try {  
            bean = (ApplicationContextBeanRegistrationOfExistingObjects) context.getBean(ApplicationContextBeanRegistrationOfExistingObjects.class);  
        } catch (BeansException e) {  
        }  
        context.getBeanFactory().registerSingleton("applicationContextBeanRegistrationOfExistingObjects", new ApplicationContextBeanRegistrationOfExistingObjects());  
        bean = (ApplicationContextBeanRegistrationOfExistingObjects) context.getBean(ApplicationContextBeanRegistrationOfExistingObjects.class);  
        System.out.println(bean);  
    }  


       SLF4J 1.6.0以前的版本,如果打印异常堆栈信息,必须用log.error(String msg, Throwable t)如果msg含有变量,一般用String.format方法格式化msg.
       如果用log.error(String format, Object... arguments)等其它方法,异常堆栈信息会丢失.
       幸好,SLF4J 1.6.0以后的版本对异常信息改进了.Log.error(String format, Object... arguments) 这个方法也会打印异常堆栈信息,只不过规定throwable对象必须为最后一个参数.如果不遵守这个规定,异常堆栈信息不会log出来.
    String s = "Hello world";
    try {
      Integer i = Integer.valueOf(s);
    } catch (NumberFormatException e) {
      logger.error("Failed to format {}", s, e);
    }



Stream<String> stream = list.stream().filter(p -> p.length() > 3);  
String[] arr = stream.toArray(String[]::new);


避免空值
       尽可能的避免使用null。不要返回集合时使用null,而应当返回一个空的集合。如果将要使用null,可以考虑使用 @Nullable 的注解。如果使用的是Java 8,可以选择更好的 Optional 类。如果一个值可能存在也可能不存在,可以把它包装为一个 Optional 类.


       集合类型,只要有可能,请使用Guava的 ImmutableMap、ImmutableList 或 ImmutableSet 类。这些已存在的建造者可以让你通过调用它们的 build 方法动态的建造不可变的集合。


Apache Commons项目提供了许多有用的库。
       Commons Codec提供了许多关于Base64和16进制字符串的编码和解码方法。
       Commons Lang提供了String类的创建、操作及字符集等一系列工具方法。
       Commons IO拥有所有文件操作相关的方法。它有 FileUtils.copyDirectory、FileUtils.writeStringToFile、IOUtils.readLines等方法。


使用EnumSet或EnumMap
       在某些情况下,比如在使用配置map时,可能会预先知道保存在map中键值。如果这个键值非常小,就应该考虑使用 EnumSet 或 EnumMap,而并非使用常用的HashSet或 HashMap。下面的代码给出了很清楚的解释:
private transient Object[] vals;
 
public V put(K key, V value) {
    // ...
    int index = key.ordinal();
    vals[index] = maskNull(value);
    // ...
}
       上段代码的关键实现在于,用数组代替了哈希表。尤其是向map中插入新值时,所要做的仅仅是获得一个由编译器为每个枚举类型生成的常量序列号。如果有一个全局的map配置(例如只有一个实例),在增加访问速度的压力下,EnumMap会获得比HashMap更加杰出的表现。原因在于EnumMap使用的堆内存比HashMap要少一位(bit),而且HashMap要在每个键值上都要调用hashCode()方法和equals()方法。
        用到类似枚举(enum-like)结构的键值时,就应该考虑将这些键值用声明为枚举类型,并将之作为 EnumMap 键。


得到当前方法的名字
    String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值