臨界資源問題
先看例子
public class SourceConflict {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (TicketCenter.currnetTicket > 0) {
System.out.println(Thread.currentThread().getName()+"賣出一張票,剩余"+ --TicketCenter.currnetTicket);
}
}
};
Thread t1 = new Thread(runnable, "t1");
Thread t2 = new Thread(runnable, "t2");
Thread t3 = new Thread(runnable, "t3");
Thread t4 = new Thread(runnable, "t4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class TicketCenter{
public static int currnetTicket = 100;
}
運行程序,四個線程共享ticket資源,會同時操作票資源,不做處理會出現(xiàn)下面的問題

image.png
解決方法一:同步代碼段
public class SynchronizedDemo {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (TicketCenter.currnetTicket > 0) {
//對象鎖
synchronized ("") {
System.out.println(Thread.currentThread().getName()+"賣出一張票,剩余"+ --TicketCenter.currnetTicket);
}
}
}
};
Thread t1 = new Thread(runnable, "t1");
Thread t2 = new Thread(runnable, "t2");
Thread t3 = new Thread(runnable, "t3");
Thread t4 = new Thread(runnable, "t4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
上面的 //對象鎖 synchronized ("") 可替換成
//類鎖 synchronized(SynchronizedDemo.class)
只要保證四個線程看到的是同一所即可,
synchronized(new SynchronizedDemo())會報錯,因為每次都會生成不同對象
好接下來我們看運行代碼結(jié)果(我們的結(jié)果不一定相同)

image.png
但是?。。。。。。。?/p>

image.png
這是因為t2賣票時,t1,t3,t4拿到資源在鎖外等待,線程切換的時候,他們看到的票數(shù)還是>0的,當t2賣出最后一張,票數(shù)為0,t1,t3,t4再做賣票動作時,會產(chǎn)生負數(shù)。
修改成這樣就好了
synchronized ("") {
if (TicketCenter.currnetTicket == 0) {
return;
}
System.out.println(Thread.currentThread().getName()+"賣出一張票,剩余"+ --TicketCenter.currnetTicket);
}
解決方法二:同步方法
public class SynchronizedFunction {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (TicketCenter.currnetTicket > 0) {
sell();
}
}
};
Thread t1 = new Thread(runnable, "t1");
Thread t2 = new Thread(runnable, "t2");
Thread t3 = new Thread(runnable, "t3");
Thread t4 = new Thread(runnable, "t4");
t1.start();
t2.start();
t3.start();
t4.start();
}
/*同步方法
靜態(tài)方法:同步鎖就是類鎖, 當前類.class
非靜態(tài)方法: 同步鎖是 this*/
public synchronized static void sell(){
if (TicketCenter.currnetTicket == 0) {
return;
}
System.out.println(Thread.currentThread().getName()+"賣出一張票,剩余"+ --TicketCenter.currnetTicket);
}
}
看結(jié)果

image.png
當需要同步的邏輯比較復雜的時候可以將他們放在方法里
解決方法三:顯示鎖
public class LockDemo {
public static void main(String[] args) {
final ReentrantLock lock = new ReentrantLock();
Runnable runnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (TicketCenter.currnetTicket > 0) {
//對臨界資源加上顯示鎖
lock.lock();
if (TicketCenter.currnetTicket <= 0) {
return;
}
System.out.println(Thread.currentThread().getName()+"賣出一張票,剩余"+ --TicketCenter.currnetTicket);
//對臨界資源釋放鎖
lock.unlock();
}
}
};
Thread t1 = new Thread(runnable, "t1");
Thread t2 = new Thread(runnable, "t2");
Thread t3 = new Thread(runnable, "t3");
Thread t4 = new Thread(runnable, "t4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
結(jié)果沒有問題,但是。。。
運行之后程序沒有停止,有大佬可以告訴我為什么嗎?