Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> java Lock和Condition的用法

java Lock和Condition的用法

編輯:關於Android編程

前面我分享了Synchronized的使用,當一個線程訪問一個對象的Synchronized方法或者代碼塊的時候,就持有了鎖,除非執行完或者遇到異常(發生異常JVM虛擬機會自動釋放鎖),才能釋放鎖,但是如果在執行代碼塊裡sleep了或者有一些耗時很久的操作,那麼鎖就一直不釋放,其他線程就會一直等待下去,Lock可以不讓其他線程一直無限等待下去,另外一種情況,當有多個線程讀寫文件的時候,讀和寫會發生沖突,寫和寫會發生沖突,讀和讀按理應該不會發生沖突,但是如果用Synchronized的話,讀和讀也會發生沖突,ReadWriteLock可以解決這個問題,有一個點需要強調下,Synchronized是java內置語言,Lock不是,當一個線程執行完Synchronized修飾的方法或代碼塊之後,JVM會自動釋放鎖,但是Lock不會,必須手動執行lock.unLock()方法來釋放鎖,否則鎖就永遠不會得到釋放。
1 Lock.lock,代碼如下:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {
    public static void main(String args[]) {
        LockObject lo = new LockObject();
        MyThread t1 = new MyThread(lo);
        MyThread t2 = new MyThread(lo);
        Thread ta = new Thread(t1,"A");
        Thread tb = new Thread(t2,"B");
        ta.start();
        tb.start();

    }
}

class LockObject {
    Lock lock = new ReentrantLock();

    public void LockFuc() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "得到了鎖");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println(Thread.currentThread().getName() + "釋放了鎖");
        }
    }
}

class MyThread implements Runnable{
    LockObject lo= null;
    public MyThread(LockObject lo){
        this.lo = lo;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        lo.LockFuc();
    }


}

開始調用了lock.lock得到鎖,然後同步代碼放到try catch中,在finally裡執行lock.unlock釋放鎖,執行結果如下:
A得到了鎖
A釋放了鎖
B得到了鎖
B釋放了鎖

2 lock.tryLock(),代碼如下:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {
    public static void main(String args[]) {
        LockObject lo = new LockObject();
        MyThread t1 = new MyThread(lo);
        MyThread t2 = new MyThread(lo);
        Thread ta = new Thread(t1, "A");
        Thread tb = new Thread(t2, "B");
        ta.start();
        tb.start();

    }
}

class LockObject {
    Lock lock = new ReentrantLock();

    public void LockFuc() {
        if (lock.tryLock()) {
            try {
                System.out.println(Thread.currentThread().getName() + "得到了鎖");

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
                System.out.println(Thread.currentThread().getName() + "釋放了鎖");
            }
        }else{
            System.out.println(Thread.currentThread().getName() + "沒有得到鎖");
        }
    }
}

class MyThread implements Runnable {
    LockObject lo = null;

    public MyThread(LockObject lo) {
        this.lo = lo;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        lo.LockFuc();
    }

}

tryLock()方法是有返回值的,它表示用來嘗試獲取鎖,如果獲取成功,則返回true,如果獲取失敗(即鎖已被其他線程獲取),則返回false,也就說這個方法無論如何都會立即返回。在拿不到鎖時不會一直在那等待,執行結果如下:
A得到了鎖
B沒有得到鎖
A釋放了鎖

3 tryLock(long time, TimeUnit unit)方法和tryLock()方法是類似的,只不過區別在於這個方法在拿不到鎖時會等待一定的時間,在時間期限之內如果還拿不到鎖,就返回false。如果如果一開始拿到鎖或者在等待期間內拿到了鎖,則返回true。

4 lockInterruptibly(),代碼如下:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {
    public static void main(String args[]) {
        LockObject lo = new LockObject();
        MyThread t1 = new MyThread(lo);
        MyThread t2 = new MyThread(lo);
        Thread ta = new Thread(t1, "A");
        Thread tb = new Thread(t2, "B");

        ta.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        tb.start();
        tb.interrupt();

    }
}

class LockObject {
    Lock lock = new ReentrantLock();

    public void LockFuc() throws InterruptedException {
        lock.lockInterruptibly();
            try {
                System.out.println(Thread.currentThread().getName() + "得到了鎖");
                while(true){
                    ;
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
                System.out.println(Thread.currentThread().getName() + "釋放了鎖");
            }
    }
}

class MyThread implements Runnable {
    LockObject lo = null;

    public MyThread(LockObject lo) {
        this.lo = lo;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try{
            lo.LockFuc();
        }catch(InterruptedException e){
            System.out.println(Thread.currentThread().getName()+"被中斷");
        }

    }

}

lock.lockInterruptibly()想獲取某個鎖時,假若此時線程A獲取到了鎖,而線程B只有在等待,那麼對線程B調用threadB.interrupt()方法能夠中斷線程B的等待過程。執行結果如下:
A得到了鎖
B被中斷

下面來看讀寫鎖ReadWriteLock,可以實現讀和讀不沖突:

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LockTest {
    public static void main(String args[]) {
        LockObject lo = new LockObject();
        MyThread t1 = new MyThread(lo);
        MyThread t2 = new MyThread(lo);
        Thread ta = new Thread(t1, "A");
        Thread tb = new Thread(t2, "B");

        ta.start();
        tb.start();

    }
}

class LockObject {
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void LockFuc(){
        lock.readLock().lock();
            try {
                System.out.println(Thread.currentThread().getName() + "得到了鎖");
                for(int i=0;i<10;i++){
                    System.out.println(Thread.currentThread().getName() + "正在進行讀操作" + i);
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.readLock().unlock();
                System.out.println(Thread.currentThread().getName() + "釋放了鎖");
            }
    }
}

class MyThread implements Runnable {
    LockObject lo = null;

    public MyThread(LockObject lo) {
        this.lo = lo;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
            lo.LockFuc();


    }

}

執行結果如下:
A得到了鎖
B得到了鎖
A正在進行讀操作0
B正在進行讀操作0
A正在進行讀操作1
B正在進行讀操作1
A正在進行讀操作2
B正在進行讀操作2
A正在進行讀操作3
B正在進行讀操作3
B正在進行讀操作4
B正在進行讀操作5
B正在進行讀操作6
B正在進行讀操作7
B正在進行讀操作8
B正在進行讀操作9
A正在進行讀操作4
A正在進行讀操作5
B釋放了鎖
A正在進行讀操作6
A正在進行讀操作7
A正在進行讀操作8
A正在進行讀操作9
A釋放了鎖
可以看到讀和讀並不沖突,但是如果有Synchronized修飾的話,會發現是沖突的。

接下來說下Condition:Condition是在java 1.5中才出現的,它用來替代傳統的Object的wait()、notify()實現線程間的協作,相比使用Object的wait()、notify(),使用Condition1的await()、signal()這種方式實現線程間協作更加安全和高效。因此通常來說比較推薦使用Condition,Conditon中的await()對應Object的wait();Condition中的signal()對應Object的notify();Condition中的signalAll()對應Object的notifyAll(),接下來看個例子,重寫生產者與消費者:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
 * 生產者與消費者問題
 */
public class ProduceConsume {
    public static void main(String[] args) {
        SyncStack ss = new SyncStack();
        Produce pd = new Produce(ss);
        Consume cs = new Consume(ss);
        Thread t1 = new Thread(pd);
        Thread t2 = new Thread(cs);
        t1.start();
        t2.start();
    }
}

/*
 * 饅頭實體類
 */
class ManTou {
    private int id;

    public ManTou(int id) {
        this.id = id;
    }

    public int getId() {
        return this.id;
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "ManTou " + getId();
    }
}

/*
 * 饅頭框類
 */
class SyncStack {
    Lock lock = new ReentrantLock();
    Condition full = lock.newCondition();
    Condition empty = lock.newCondition();
    int index = 0;
    ManTou[] mtArray = new ManTou[6];

    public void push(ManTou mt) {
        lock.lock();
        try {
            while (index == mtArray.length) {
                try {
                    full.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            empty.signal();
            mtArray[index] = mt;
            index++;
            System.out.println("生產了" + mt);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void pop() {
        lock.lock();
        try {
            while (index == 0) {
                try {
                    empty.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            full.signal();
            index--;
            System.out.println("消費了" + mtArray[index]); 
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

/*
 * 生產者
 */
class Produce implements Runnable {
    SyncStack ss = null;

    public Produce(SyncStack ss) {
        this.ss = ss;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 20; i++) {
            ManTou mt = new ManTou(i);
            if (ss != null) {
                ss.push(mt);
            }
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

/*
 * 消費者
 */
class Consume implements Runnable {
    SyncStack ss = null;

    public Consume(SyncStack ss) {
        this.ss = ss;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 20; i++) {
            if (ss != null) {
                ss.pop();
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

跟之前Object的wait()、notify()的寫法很類似。
以上如有問題,歡迎指正,謝謝。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved