刚学Java不久,这里记录日常工作和学习中遇见的问题,都是入门级知识点。
1. Uninstall intellij
由于本地的Jetty一直跑不起来,已经影响到日常的开发工作,在报错实在没有办法解决的情况下,只能选择格式化重来,在此我表示很伤心。好吧,那就伤心地记录下intellij idea卸载的过程
macos上选择应用程序intellij,将其移动到废纸篓里面,这样其实不能干净卸载intellij,按照下面步骤可以清理干净:
rm -rf /Library//Preferences/IdeaIC13
rm -rf /Library//Caches/IdeaIC13
rm -rf /Library//Application Support/IdeaIC13
rm -rf /Library/Logs/IdeaIC13
清理掉Config, System, Plugins, Logs 应该就干净了。
2. Maven Jetty启动报错:PermGen space
报错内容如下:
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 20 seconds.
But at the first scan i get the following error:
ERROR ContextLoader - Context initialization failed
java.lang.OutOfMemoryError: PermGen space
解决方法,加上:-Xmx1024m -Xms1024m -XX:PermSize=512m
有时候我们需要远程调试,IDea支持远程调试功能:
将Host和Port改成远程机器的IP和端口,那么远程JVM启动的时候加上参数:
JVM_ARGS ="****(其他参数) -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8417"
3. Java 主线程和子线程的关系
Java认为:并不存在java的主线程和子线程之分,都只是个普通的线程。进程的资源是线程共享的,只要进程还在,线程就可以正常执行,换句话说线程是强依赖于进程的。也就是说,线程其实并不存在互相依赖的关系,一个线程的死亡从理论上来说,不会对其他线程有什么影响。JVM可以理解为进程,只要JVM还在线程就有执行的机会。
这点跟Golang不同,Golang里面主协程一旦退出,子协程就没有执行的机会了,Golang是通过Channel完成多协程之间的通信。
4. Java 多线程的创建
(1) 继承Thread
class CustomThread extends Thread {
@Override
public void run() {
System.out.println("子线程ID:"+Thread.currentThread().getId());
System.out.println("我继承Thread类,处理任务的逻辑");
}
}
public class MoreThread {
public static void main(String[] args) {
System.out.println("主线程ID:"+Thread.currentThread().getId());
new CustomThread().start();
}
}
(2) 实现Runnable
class MyThread implements Runnable {
@Override
public void run() {
System.out.println("子线程ID:"+Thread.currentThread().getId());
System.out.println("我实现Runnable接口, 处理任务的逻辑");
}
}
public class MoreThread {
public static void main(String[] args) {
System.out.println("主线程ID:"+Thread.currentThread().getId());
new Thread(new MyThread()).start();
}
}
(3) ExecutorService、Callable、Future有返回结果的多线程
class CallableImpl implements Callable<Integer> {
public Integer call() throws Exception {
Integer sum = 0;
System.out.println("Callable子线程开始计算啦!");
for (int i=0; i<50; i++){
sum = sum + I;
}
System.out.println("Callable子线程计算结束!");
return sum;
}
}
public class MoreThread {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
CallableImpl callable = new CallableImpl();
Future<Integer> future = executorService.submit(callable);
executorService.shutdown();
try{
Thread.sleep(2000);
System.out.println("主线程有其他任务在执行");
if (future != null && future.get() != null) {
System.out.println("future.get()-->"+future.get());
} else {
System.out.println("future.get()未获取到结果");
}
}catch (Exception e) {
e.printStackTrace();
}
System.out.println("主线程在执行完成");
}
}
5. Java 泛型
Java泛型出来之前,java是如何做泛型的呢?
private static void print(Object object) {
System.out.println(object.getClass().getName().toString());
if (object instanceof Integer) {
System.out.println(1);
} else if (object instanceof String) {
System.out.println("cd1");
}
}
是的,通过反射或者强制类型转化来达到类型匹配的目的。Java中的Object
就相当于Golang中的interface
,容纳一切类型。
Java的泛型非常强大,强大到无处不在。同时Java的泛型只在编译阶段有效,在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。http://www.jianshu.com/p/95f349258afb 和http://blog.csdn.net/s10461/article/details/53941091文章写得不错。
Java中泛型分为:泛型类,泛型方法,泛型接口三大类。Java的泛型通配符?, T, K,V,E的含义:
? 表示不确定的java类型
** T (type)** 表示具体的一个java类型
K V (key value) 分别代表java键值中的Key Value
E (element) 代表Element
6. Maven
maven是java中非常棒的包管理工具,如果你想发布一个jar包到平台上去,只需要执行:mvn deploy
。但经常会出现:
Error occurred during initialization of VM
Too small initial heap
解决方法:
export MAVEN_OPTS=-Xmx1024m
加到环境变量里面,然后 source /etc/profile
即可。
7. ThreadLocal
先给出它的用途,ThreadLocal和Synchonized都用于解决多线程并发訪问。但它们有本质的不同,Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
这里想问一个问题,Golang为什么不搞一个thread local storage呢?Rob Pike先生是如何看待threadLocal这个东西的呢?
8. DispatcherServlet
Spring是通过DispatcherServlet ->FrameworkServlet->HttpServletBean->HttpServlet->GenericServlet->Servlet,最终实现了Servlet接口,DispatcherServlet又叫前置控制器。DispatcherServlet的主要工作流程如下:
- 前端请求到达DispatcherServlet。
- 前端控制器请求HandlerMappering 查找Handler。
- 如果查找到存在的处理器,进一步去调用service和dao层
- 返回结果再到controller层,渲染具体的视图,返回结果给页面。
9. Synchronized
类方法中synchronized锁住的是对象this,只有调用同一个对象的方法才需要获取锁。
静态方法中synchronized锁住的是类,该类中所有加了synchronized的静态方法,一次只能调用一个。
这里必须强调的是:当一个对象被创建时候,JVM会为这个对象创建一个自引用的指针this,所以this只能在类的非静态方法中使用,this和对象之间是一一对应关系,不是和类一一对应,这个需要特别注意的点。同一个类的不同实例(对象)this不是一个东西。
10. JVM锁优化
对象锁的状态分为四种: 无锁,轻量级锁,重量级锁和偏向锁。偏向锁是JDK1.6提出来的一种锁优化的机制,默认是开启的。这么多锁的目的是为了尽可能提高锁的性能,降低锁带来的系统性能损耗。http://blog.csdn.net/zhxdick/article/details/61916359
11. Java Reference
Java的引用分四个级别:强,软(SoftReference),弱(WeakReference),虚(PhantomReference);
强引用就是普通引用,A a1=new A(); A a2 = a1; 当所有A的引用a1, a2都失效之后,new出来的A()对象才能被回收。如果对象的内存大小超出之后,直接报“java.lang.OutOfMemoryError”。
软引用用来描述还有用并非必要的对象,在系统将要发生内存溢出异常之前,将会把这些对象列入回收范围进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。
弱引用也是用来描述非必要对象的,但是他的强度比软引用更弱一些,被软引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。
一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获取一个对象的实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。