原理
注意 除非特殊说明,以下所说的计算 Java 对象大小,不涉及该对象所持有的对象本身的大小,只计算该 Java 对象本身的大小(其中引用类型对象大小只计算为 4 bytes),如果要遍历计算 Java 对象大小(包含其持有对象的大小)可以参考这篇文章 Sizeof for Java
为什么匿名内部类
使用局部引用
要用final
?
先说结论:
由于 JAVA 匿名内部类的实现并不是真正的闭包,而是在生成内部类的时候将局部变量的引用拷贝了一份到内部类中。如果不将这个外部类设置为final
的话,外部类或者内部类修改这个局部变量后,另外一处使用的仍然是修改前的值,这样就会产生问题,而如果将其修改为final
则保证了局部变量与内部类使用的值是一致的。
JDK1.8 后局部变量不要求用final
了?
ThreadLocal
是Thread
中用来保存线程私有变量的数据结构。
一个ThreadLocal
只能保存一个值,有set/get/remove
方法。
在Thread
有一个threadLocals
(ThreadLocal.ThreadLocalMap
)变量,该变量是一个定制的 Hash Map,用来保存线程私有的数据(类型为ThreadLocal<?> Key, Object Value
)。
Thread.join()
cThread.join()
方法使当前线程阻塞,直到子线程cThread
执行完毕后,当前线程才会恢复运行。
实现原理:
-
join()
方法调用了join(0)
public final void join() throws InterruptedException { join(0); }
-
join(long millis)
是一个同步方法,最后会通过调用wait()
方法挂起当前线程(即调用线程
),直到其他线程调用子线程cThread
的notify()
或者notifyAll()
方法public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
-
子线程
run()
执行完毕后,系统在关闭该子线程前,会调用其exit()
方法,继而在ThreadGroup.threadTerminated(Thread t)
中唤醒被阻塞的调用线程。/** * This method is called by the system to give a Thread * a chance to clean up before it actually exits. */ private void exit() { if (group != null) { group.threadTerminated(this);//提心 ThreadGroup 当前线程已经被终止 group = null; } //其他代码 …… } // ThreadGroup void threadTerminated(Thread t) { synchronized (this) { remove(t); if (nthreads == 0) {//线程组线程数为0时 notifyAll();//唤醒所有等待中的线程 } if (daemon && (nthreads == 0) && (nUnstartedThreads == 0) && (ngroups == 0)) { destroy(); } } }
Java 中的泛型实现了参数类型化的概念。
主要有以下形式:
class OneClazz<T>{
T t;
<Y> void fun(){}
}
简介
在编码中常常会用到单例,来确保类有一个唯一的对象,一般情况下将构造方法私有化既可以实现,但当考虑到多线程时事情会变得有些复杂,本文讨论的正是几种多线程的情况下实现单例的方法。
1.普通单例
私有化构造方法,对外提供一个公有、静态的方法,在其内部判断类对象是否已经存在,否的话生成类对象再返回。
class ASingleton{
private static ASingleton as;
private void ASinleton() {
System.out.print("ASingleton init!\n");
}
public static ASingleton getInstance() {
if(as == null) { //tag1
as = new ASingleton(); //tag2
}
return as;
}
}
简介
反射,用来在运行时获取给定类的构造函数,变量,方法,并对其作以修改,而不必在编译时获取该类。
Reflection allows programmatic access to information about the fields, methods and constructors of loaded classes, and the use of reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
--https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html