java中ReentrantLock類的tryLock和tryLock的例子和用法

ReentrantLock類的tryLock和tryLock(時(shí)間)
馬克-to-win:tryLock的方法就是試一下,如果能得到鎖,就返回真,如果當(dāng)時(shí)得不到,馬上就返回假,絕不等。tryLock(時(shí)間)的用法就是在規(guī)定的時(shí)間內(nèi)設(shè)法得到鎖。如果在規(guī)定的時(shí)間內(nèi)最終不能得到鎖,就返回假。注意,這個(gè)方法是可以被打斷的,打斷后的處理方法和上面的例子 lockInterruptibly的處理一樣。馬克- to-win:馬克 java社區(qū):防盜版實(shí)名手機(jī)尾號(hào): 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("沒(méi)獲得鎖,一張");
        }
    }

    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)獲得了鎖了,幾張的睡覺(jué)被打斷,表示預(yù)備工作沒(méi)做好,什么也不買");
            }
            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("沒(méi)獲得鎖,幾張");
        }
    }
}

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("正要獲得鎖的過(guò)程當(dāng)中呢,幾張的線程被打斷");
        }
    }
}
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);根本沒(méi)得到鎖)運(yùn)行結(jié)果:
just before lock.lockInterruptibly();
Thread-0ticketNum is10
just before lock.lockInterruptibly();
just before lock.lockInterruptibly();
沒(méi)獲得鎖,一張
沒(méi)獲得鎖,幾張
模仿select * from table for update,執(zhí)行的很慢,買了一張Thread-0ticketNum is9



例1.9.8_b:(只需要把上面實(shí)驗(yàn)的主程序改變一下就行,其他都不用變。)

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);正要獲得鎖的過(guò)程當(dāng)中被打斷了)運(yùn)行結(jié)果:
just before lock.lockInterruptibly();
Thread-0ticketNum is10
just before lock.lockInterruptibly();
just before lock.lockInterruptibly();
沒(méi)獲得鎖,一張
正要獲得鎖的過(guò)程當(dāng)中呢,幾張的線程被打斷
模仿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);獲得了鎖)運(yùn)行結(jié)果:

just before lock.lockInterruptibly();
Thread.currentThread().getName()+ticketNum is10
just before lock.lockInterruptibly();
沒(méi)獲得鎖,一張
just before lock.lockInterruptibly();
沒(méi)獲得鎖,一張
模仿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是排在隊(duì)列里第一個(gè)的,根本不用等,更別說(shuō)是等2秒,2秒是真正等時(shí)的極限?!空诟墒碌牡倪^(guò)程當(dāng)中被打斷了)運(yùn)行結(jié)果:


just before lock.lockInterruptibly();
Thread.currentThread().getName()+ticketNum is10
just before lock.lockInterruptibly();
沒(méi)獲得鎖,一張
just before lock.lockInterruptibly();
沒(méi)獲得鎖,一張
已經(jīng)獲得了鎖了,幾張的睡覺(jué)被打斷,表示預(yù)備工作沒(méi)做好,什么也不買



volatile關(guān)鍵字與原子操作

volatile關(guān)鍵字到底是干什么的?(新手可略過(guò))

我們先簡(jiǎn)要了解一下java虛擬機(jī)的內(nèi)存模型。就像數(shù)據(jù)從物理內(nèi)存拷貝到cpu高速緩存,進(jìn)行操作完,再把數(shù)據(jù)返回到內(nèi)存一樣,為了屏蔽CPU高速緩存和內(nèi)存復(fù)雜細(xì)節(jié)且贏得跨平臺(tái)的效果,java把所有的變量都存在主存(相當(dāng)于物理內(nèi)存)當(dāng)中,每個(gè)線程都有自己的工作內(nèi)存(相當(dāng)于CPU高速緩存)。線程在自己的工作內(nèi)存做操作,不能直接對(duì)主存進(jìn)行操作,最后把結(jié)果返回到主存。如果一個(gè)變量有volatile(易變的意思)修飾詞,這意味著當(dāng)有一個(gè)線程修改了這個(gè)變量,系統(tǒng)會(huì)把工作內(nèi)存當(dāng)中的變化強(qiáng)制立刻反應(yīng)在主存當(dāng)中。其他線程要想讀這個(gè)變量,也會(huì)被強(qiáng)迫讀變化了的新值。volatile其實(shí)就保證了此變量無(wú)論怎么變,任何線程看都是最新的。當(dāng)兩個(gè)線程,根據(jù)一個(gè)共同的信號(hào),做互動(dòng)時(shí),一定要加volatile,保證這個(gè)信號(hào)是最新的。

volatile,有人說(shuō)能夠控制程序的語(yǔ)句有序性,但jvm并不能保證在所有的平臺(tái)上都能夠做到這一點(diǎn),所以我的書中就不贅述了。既然volatile控制程序語(yǔ)句的有序性不能保證所有的平臺(tái)都正確運(yùn)行,基于它的技術(shù)“雙重檢查鎖”創(chuàng)建單態(tài)對(duì)象也就變得不可靠了,本書也就不覆蓋了。