java中ReentrantLock類的tryLock和tryLock的例子和用法
ReentrantLock類的tryLock和tryLock(時間)
馬克-to-win:tryLock的方法就是試一下,如果能得到鎖,就返回真,如果當時得不到,馬上就返回假,絕不等。tryLock(時間)的用法就是在規(guī)定的時間內(nèi)設法得到鎖。如果在規(guī)定的時間內(nèi)最終不能得到鎖,就返回假。注意,這個方法是可以被打斷的,打斷后的處理方法和上面的例子 lockInterruptibly的處理一樣。馬克- to-win:馬克 java社區(qū):防盜版實名手機尾號: 73203。
例1.9.8_a:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
class A {
private ReentrantLock lock = new ReentrantLock();
int ticketNum = 10;
public void buyOne() {
System.out.println("just before lock.lockInterruptibly();");
boolean succeed = lock.tryLock();
if (succeed) {
System.out.println(Thread.currentThread().getName()
+ "ticketNum is" + ticketNum);
if (ticketNum > 0) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticketNum--;
System.out
.println("模仿select * from table for update,執(zhí)行的很慢,買了一張"
+ Thread.currentThread().getName()
+ "ticketNum is" + ticketNum);
}
lock.unlock();
}else{
System.out.println("沒獲得鎖,一張");
}
}
public void buyBatch(int num) throws InterruptedException {
System.out.println("just before lock.lockInterruptibly();");
boolean succeed = false;
boolean sleepSucceed = false;
succeed = lock.tryLock(2, TimeUnit.SECONDS);
if (succeed) {
System.out.println("Thread.currentThread().getName()+ticketNum is"
+ ticketNum);
try {
Thread.sleep(5000);
sleepSucceed=true;
} catch (InterruptedException e) {
System.out.println("已經(jīng)獲得了鎖了,幾張的睡覺被打斷,表示預備工作沒做好,什么也不買");
}
if (ticketNum >= num&&sleepSucceed) {
ticketNum = ticketNum - num;
System.out
.println("模仿select * from table for update,執(zhí)行的很慢,買了幾張"
+ Thread.currentThread().getName()
+ "ticketNum is" + ticketNum);
}
lock.unlock();
}else{
System.out.println("沒獲得鎖,幾張");
}
}
}
class MyThread1 extends Thread {
A a;
public MyThread1(A a) {
this.a = a;
}
public void run() {
a.buyOne();
}
}
class MyThread2 extends Thread {
A a;
public MyThread2(A a) {
this.a = a;
}
public void run() {
try {
a.buyBatch(3);
} catch (InterruptedException e) {
System.out.println("正要獲得鎖的過程當中呢,幾張的線程被打斷");
}
}
}
public class TestMark_to_win {
public static void main(String[] args) throws InterruptedException {
MyThread1[] threads = new MyThread1[2];
A a = new A();
for (int i = 0; i < 2; i++) {
threads[i] = new MyThread1(a);
}
MyThread2 myThread2 = new MyThread2(a);
threads[0].start();
Thread.sleep(50);
myThread2.start();
threads[1].start();
// Thread.sleep(50);
// myThread2.interrupt();
}
}
(這種情況是tryLock(2, TimeUnit.SECONDS);根本沒得到鎖)運行結(jié)果:
just before lock.lockInterruptibly();
Thread-0ticketNum is10
just before lock.lockInterruptibly();
just before lock.lockInterruptibly();
沒獲得鎖,一張
沒獲得鎖,幾張
模仿select * from table for update,執(zhí)行的很慢,買了一張Thread-0ticketNum is9
例1.9.8_b:(只需要把上面實驗的主程序改變一下就行,其他都不用變。)
public class TestMark_to_win {
public static void main(String[] args) throws InterruptedException {
MyThread1[] threads = new MyThread1[2];
A a = new A();
for (int i = 0; i < 2; i++) {
threads[i] = new MyThread1(a);
}
MyThread2 myThread2 = new MyThread2(a);
threads[0].start();
Thread.sleep(50);
myThread2.start();
threads[1].start();
Thread.sleep(50);
myThread2.interrupt();
}
}
(這種情況是tryLock(2, TimeUnit.SECONDS);正要獲得鎖的過程當中被打斷了)運行結(jié)果:
just before lock.lockInterruptibly();
Thread-0ticketNum is10
just before lock.lockInterruptibly();
just before lock.lockInterruptibly();
沒獲得鎖,一張
正要獲得鎖的過程當中呢,幾張的線程被打斷
模仿select * from table for update,執(zhí)行的很慢,買了一張Thread-0ticketNum is9
例1.9.8_c:
public class TestMark_to_win {
public static void main(String[] args) throws InterruptedException {
MyThread1[] threads = new MyThread1[2];
A a = new A();
for (int i = 0; i < 2; i++) {
threads[i] = new MyThread1(a);
}
MyThread2 myThread2 = new MyThread2(a);
myThread2.start();
Thread.sleep(50);
threads[0].start();
threads[1].start();
// Thread.sleep(50);
// myThread2.interrupt();
}
}
(這種情況是tryLock(2, TimeUnit.SECONDS);獲得了鎖)運行結(jié)果:
just before lock.lockInterruptibly();
Thread.currentThread().getName()+ticketNum is10
just before lock.lockInterruptibly();
沒獲得鎖,一張
just before lock.lockInterruptibly();
沒獲得鎖,一張
模仿select * from table for update,執(zhí)行的很慢,買了幾張Thread-2ticketNum is7
例1.9.8_d:
public class TestMark_to_win {
public static void main(String[] args) throws InterruptedException {
MyThread1[] threads = new MyThread1[2];
A a = new A();
for (int i = 0; i < 2; i++) {
threads[i] = new MyThread1(a);
}
MyThread2 myThread2 = new MyThread2(a);
myThread2.start();
Thread.sleep(50);
threads[0].start();
threads[1].start();
Thread.sleep(50);
myThread2.interrupt();
}
}
(這種情況是tryLock(2, TimeUnit.SECONDS);已經(jīng)獲得了鎖,【注意雖然寫的是2秒,但是myThread2是排在隊列里第一個的,根本不用等,更別說是等2秒,2秒是真正等時的極限。】正在干事的的過程當中被打斷了)運行結(jié)果:
just before lock.lockInterruptibly();
Thread.currentThread().getName()+ticketNum is10
just before lock.lockInterruptibly();
沒獲得鎖,一張
just before lock.lockInterruptibly();
沒獲得鎖,一張
已經(jīng)獲得了鎖了,幾張的睡覺被打斷,表示預備工作沒做好,什么也不買
volatile關鍵字與原子操作
volatile關鍵字到底是干什么的?(新手可略過)
我們先簡要了解一下java虛擬機的內(nèi)存模型。就像數(shù)據(jù)從物理內(nèi)存拷貝到cpu高速緩存,進行操作完,再把數(shù)據(jù)返回到內(nèi)存一樣,為了屏蔽CPU高速緩存和內(nèi)存復雜細節(jié)且贏得跨平臺的效果,java把所有的變量都存在主存(相當于物理內(nèi)存)當中,每個線程都有自己的工作內(nèi)存(相當于CPU高速緩存)。線程在自己的工作內(nèi)存做操作,不能直接對主存進行操作,最后把結(jié)果返回到主存。如果一個變量有volatile(易變的意思)修飾詞,這意味著當有一個線程修改了這個變量,系統(tǒng)會把工作內(nèi)存當中的變化強制立刻反應在主存當中。其他線程要想讀這個變量,也會被強迫讀變化了的新值。volatile其實就保證了此變量無論怎么變,任何線程看都是最新的。當兩個線程,根據(jù)一個共同的信號,做互動時,一定要加volatile,保證這個信號是最新的。
volatile,有人說能夠控制程序的語句有序性,但jvm并不能保證在所有的平臺上都能夠做到這一點,所以我的書中就不贅述了。既然volatile控制程序語句的有序性不能保證所有的平臺都正確運行,基于它的技術“雙重檢查鎖”創(chuàng)建單態(tài)對象也就變得不可靠了,本書也就不覆蓋了。