自己经验有限,篇幅也有限,这里只是记录一些比较容易混淆或有难度和一些易忘的技术知识点,里面有一些也是面试阿里经常会被问到的问题,但是不保证答案全部正确,有错误的地方望大家指正
-Xms
和-Xmx
栈(以前概括都叫栈,具体说其实是非堆内存):一般是线程私有 Object
的hashCode()
;虚拟机栈中用于存储局部变量表、动态链接、操作数、方法出口等信息finalize()
),如果没有下一次判定对象死亡;基础的复制算法我举个例子说明,将一块内存分成2份,运行时只使用其中一块,GC时将活的对象复制到另一块内存,然后清除前一块所有内存空间,类似于给U盘格式化,这样比一个一个释放内存要快得多,相信大家做格式化的时候体会过,现在jvm gc使用的的复制算法是结果改良的,不是平均的分成2份,默认比例好像是1/8,即平常见到的新生代、老年代、持久代等。具体的算法大家看资料文档吧,这种东西不是说说就能清楚的。Object o1 = new Object();
Object o2 = new Object();
o1 = o2; // 这时2个对象的引用地址是一样的,但是o1申请的内存就没有被使用
内存泄漏积累多了,内存不断被无用对象占用,新的对象申请不到足够的空间就会产生内存溢出。
DispatcherServlet
将请求转发给对应的@Controller
和@RequestMapping
Model
等ModelAndView
查找ViewResolver
返回对应的View
,可能是需要渲染的jsp,可能是json,可能是文件流等等。redis
里的bitmap
bitmap
一般用于计数或top计算,比如统计网站当前在线人数,假设用户id是递增的整数,当用户上线时将用户id存进bitmap,比如id是4,则bitmap就是00001000
,id为8的用户上线,bitmap的值变成10001000
,对bitmap做count计算得出是2,而1KB=1024B=8196b且位运算是计算机最快的,这样做的好处是速度快,还能知道是谁上下线的。同理如果要按月统计某个操作,只需要用每天做key值,然后做并集得到新的bitset计数就可。InvocationHandler
接口可以方便实现动态代理:public interface IService {
void service();
}
public class MyService implements IService {
@Override
public void service() {
System.out.println("service...");
}
}
public class MyProxy implements InvocationHandler {
private IService service;
public MyProxy(IService service) {
this.service = service;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before service");
Object invoke = method.invoke(service, args);
System.out.println("after service ");
return invoke;
}
}
public class Main {
public static void main(String[] args) {
MyService myService = new MyService();
MyProxy myProxy = new MyProxy(myService);
// 动态生成代理对象
IService instance = (IService) Proxy.newProxyInstance(MyService.class.getClassLoader(), MyService.class.getInterfaces(), myProxy);
instance.service();// 利用代理对象调用service方法
}
}
lock table_name read
or write
;InnoDB采用的是行级锁,只锁行,效率高,但是会死锁,另外MySQL的行级锁采用锁索引实现,所以只有通过索引检索数据才能使用行级锁,否则会使用表级锁ConcurrentHashMap
是线程安全的集合类,功能类似于Hashtable
,但是Hashtable
虽然也是线程安全的,但是Hashtable
只有一把同步锁,并发性能不高,ConcurrentHashMap
则是利用了锁分段技术,简单来说就是,多个类似的HashTable
,单独维护自己的锁,这样多线程操作的时候减少了竞争锁的等待,在多线程应用里是最常用的线程安全集合类。查看源码可以知道,ConcurrentHashMap
内部主要成员是Segment
和Node
,Segment
充当锁,继承ReentrantLock
,Node
相当于一个Map.Entry
,其他大部分成员变量都是volatile
的,因为happen before
的存在,volatile
字段的写入操作先于读操作,这也是用volatile替换锁的经典应用场景。volatile
替换同步锁ThreadLocal
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
public class Test {
/**
* 根据map的value进行排序
* @param map
* @param <K>
* @param <V>
* @return
*/
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(map.entrySet());
// 先将map转换成List便于使用sort排序
Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
return (o2.getValue()).compareTo(o1.getValue());
}
});
Map<K, V> result = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
public static void main(String[] args) {
FileInputStream fileInputStream = null;
String fileName = "ngen.log";
TreeMap<String, Integer> map = new TreeMap<>();
// SortedMap<String, Integer> map = new
try {
fileInputStream = new FileInputStream(fileName);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
String line = null;
// 按行读取文件分解单词
while ((line = bufferedReader.readLine()) != null) {
String[] ss = line.split(" ");
for (int i = 0; i < ss.length; i++) {
String s = ss[i];
if (s != null && s.matches("\\w+")) {
// 如果map中有此单词就将次数+1
// 否则此单词第一次出现
if (map.containsKey(s)) {
map.put(s, map.get(s) + 1);
} else {
map.put(s, 1);
}
}
}
}
Map<String, Integer> sortedMap = sortByValue(map);
for (Map.Entry<String, Integer> entry : sortedMap.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + ":" + value);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
1.8:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
/**
* 根据map的value进行排序
* @param map
* @param <K>
* @param <V>
* @return
*/
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
return map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue(Collections.reverseOrder())) // 逆序
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
}
public static void main(String[] args) {
FileInputStream fileInputStream = null;
String fileName = "D:/app.log";
TreeMap<String, Integer> map = new TreeMap<>();
try {
fileInputStream = new FileInputStream(fileName);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
bufferedReader.lines()
.flatMap(line -> Stream.of(line.split(" ")))
.filter(word -> word.matches("\\w+"))
.forEach(s -> { // Stream语法不太熟悉,不知道有木有更方便的方法?
if (map.containsKey(s)) {
map.put(s, map.get(s) + 1);
} else {
map.put(s, 1);
}
})
;
Map<String, Integer> sortedMap = sortByValue(map);
sortedMap.forEach((k, v) -> System.out.println(k + "," + v));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
本文已在版权印备案,如需转载请访问版权印。40142943