一、不要使用常量作为锁,比如String
以String为例,字符串是存在于常量池当中的,比如下面两个字符串a和b,这两个字符串的内容一样,他们的地址就会相同,
String a = "abc";
String b = "abc";
用下面的代码来说明,定义两个字符串a和b,在main方法中创建两个线程 ,分别取名为thread1和thread2;
首先,thread1线程会先执行,此时由于对象锁a是处于未被占有状态,因此thread1会直接拿到锁,并执行打印;
之后,thread2线程执行,因为对象锁b也是处于未被占有的状态,讲道理,会直接拿到锁并执行打印;
但是执行结果1却显示并没有打印thread2,这是因为a和b根本就是同一个对象,当thread1拿到锁a,并且在没有释放锁的情况下,锁"abc"(这里即:对象锁b)将是其他线程得不到的那个男人;
当我们将锁的类型换成Object时,就会得到另一番景象,执行结果2显示 thread1和thread1都各自拿到了锁,并执行打印;
public class ThreadConstant {
// a和b对象地址相同
String a = "abc";
String b = "abc";
// a和b对象地址不同
// Object a = new Object();
// Object b = new Object();
private void getThread1(){
synchronized (a){
while (true) {
System.out.println(Thread.currentThread());
}
}
}
private void getThread2(){
synchronized (b){
while (true) {
System.out.println(Thread.currentThread());
}
}
}
public static void main(String[] args) {
ThreadConstant tc = new ThreadConstant();
new Thread(()->{
tc.getThread1();
}, "thread1").start();
new Thread(()->{
tc.getThread2();
}, "thread2").start();
}
}
执行结果1:thread1拿到锁,执行打印,,thread2未拿到锁,进入等待
执行结果2:thread1拿到锁,执行打印,,thread2拿到锁,执行打印。
二、不要在偏向锁的时候进行hashcode
在对象头里有块区域为markword
如果在无锁状态下,markword前25位一般是用来存放对象的hash值的
如果是偏向锁状态,那么markword前25位则是用来存储线程的id
因此,如果你进行了hashcode,那么该区域就只能用于存储hash值,就无法存放线程id了