不要使用字符串常量作為對(duì)象鎖去同步代碼
synchronized是對(duì)象鎖眨层,但是對(duì)于這個(gè)Java內(nèi)置的對(duì)象鎖如果理解不深入可能就會(huì)踩到坑毅贮。請(qǐng)看下面的例子:
public class DeadLockDemo {
private static String A = "A";
private static String B = "B";
public static void main(String[] args) {
new DeadLockDemo().deadLock();
}
private void deadLock() {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (A) {
try { Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (B) {
System.out.println("1");
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (B) {
synchronized (A) {
System.out.println("2");
}
}
}
});
t1.start();
t2.start();
}
}
上面是一個(gè)死鎖的例子,用來演示死鎖是沒有問題康震,但是大家有沒有注意privat static String A = "A"幻馁,它使用字符串常量作為對(duì)象鎖尼夺,大家認(rèn)為這個(gè)有問題嗎?請(qǐng)看下面這個(gè)例子绍些。
public class NotifyTest {
private String flag = "true";
class NotifyThread extends Thread {
public NotifyThread(String name) {
super(name);
}
public void run() {
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (flag) {
//flag的對(duì)象變?yōu)閒alse,對(duì)象發(fā)生改變
flag = "false";
flag.notifyAll();
}
}
}
class WaitThread extends Thread {
public WaitThread(String name) {
super(name);
}
public void run() {
synchronized (flag) {
while (flag.equals("true")) {
System.out.println(getName() + " begin waiting!");
long waitTime = System.currentTimeMillis();
try {
flag.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
waitTime = System.currentTimeMillis() - waitTime;
System.out.println("wait time :" + waitTime);
}
System.out.println(getName() + " end waiting!");
}
}
}
public static void main(String[] args) throws InterruptedException {
System.out.println("Main Thread Run!");
NotifyTest test = new NotifyTest();
NotifyThread notifyThread = test.new NotifyThread("notify01");
WaitThread waitThread01 = test.new WaitThread("waiter01");
notifyThread.start();
waitThread01.start();
}
}
運(yùn)行結(jié)果:
Main Thread Run!
waiter01 begin waiting!
Exception in thread "notify01" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at juc.NotifyTest$NotifyThread.run(NotifyTest.java:24)
為什么會(huì)出現(xiàn)上面的情況:問題主要是flag對(duì)象的引用發(fā)生了改變捞慌,我們?nèi)绾芜x擇synchoronize的鎖呢,其實(shí)只要我們將flag換為javaBean就行柬批,現(xiàn)在為了方便起見我們使用String數(shù)組private String flag[] = {"true"}這樣也可以解決問題啸澡。例子如下:
package juc;
/**
* Created by wjk on 2017/7/25.
*/
public class NotifyTest {
private String flag[] = {"true"};
class NotifyThread extends Thread {
public NotifyThread(String name) {
super(name);
}
public void run() {
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (flag) {
//flag的對(duì)象變?yōu)閒alse,對(duì)象發(fā)生改變
flag[0] = "false";
flag.notifyAll();
}
}
}
class WaitThread extends Thread {
public WaitThread(String name) {
super(name);
}
public void run() {
synchronized (flag) {
while (flag[0].equals("true")) {
System.out.println(getName() + " begin waiting!");
long waitTime = System.currentTimeMillis();
try {
flag.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
waitTime = System.currentTimeMillis() - waitTime;
System.out.println("wait time :" + waitTime);
}
System.out.println(getName() + " end waiting!");
}
}
}
public static void main(String[] args) throws InterruptedException {
System.out.println("Main Thread Run!");
NotifyTest test = new NotifyTest();
NotifyThread notifyThread = test.new NotifyThread("notify01");
WaitThread waitThread01 = test.new WaitThread("waiter01");
notifyThread.start();
waitThread01.start();
}
}