1. 程式人生 > >Java小題目之兩個執行緒順序列印A、B

Java小題目之兩個執行緒順序列印A、B

1、問題描述

使用Java多執行緒方式來實現迴圈列印A、B,並保證不亂序。

2、解決方案

java在編寫多執行緒程式時,為了保證執行緒安全,需要對資料同步,經常用到兩種同步方式就是Synchronized和重入鎖ReentrantLock。

  1. 利用synchronized關鍵字來實現
package org.ibenben.test;

public class OrderThreadTest {

    public static void main(String[] args){
        OrderThreadTest test = new OrderThreadTest();

        Object lock
= new Object(); test.new Output(lock, "A").start(); test.new Output(lock, "B").start(); } class Output extends Thread{ private Object lock; private String value; public Output(Object lock,String value) { this.lock = lock; this
.value = value; } @Override public void run() { synchronized (lock) { while (true) { try { System.out.println(value); lock.notifyAll(); lock
.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }

2.使用ReentrantLock來實現

package org.ibenben.test;

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

public class OrderThreadTest {
    private ReentrantLock lock = new ReentrantLock();
    Condition aCondition = lock.newCondition();
    Condition bCondition = lock.newCondition();

    public static void main(String[] args){
        OrderThreadTest test = new OrderThreadTest();

        test.new AOutput().start();
        test.new BOutput().start();
    }

    class AOutput extends Thread{

        @Override
        public void run() {
            while (true) {                              
                try {
                    lock.lock();
                    System.out.println("A");

                    bCondition.signal();
                    aCondition.await(); 
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }   
        }   
    }

    class BOutput extends Thread{

        @Override
        public void run() {
            while (true) {                              
                try {
                    lock.lock();
                    System.out.println("B");
                    aCondition.signal();
                    bCondition.await(); 
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        }   
    }
}

3、Synchronized與ReentrantLock

ReentrantLock與synchronized關鍵字一樣,屬於互斥鎖,synchronized中的鎖是非公平的(公平鎖是指多個執行緒等待同一個鎖時,必須按照申請鎖的時間順序來依次獲得鎖),ReentrantLock預設情況下也是非公平的,但可以通過帶布林值的建構函式要求使用公平鎖。執行緒通過ReentrantLock的lock()方法獲得鎖,用unlock()方法釋放鎖。

ReentrantLock和synchronized關鍵字的區別

  1. ReentrantLock在等待鎖時可以使用lockInterruptibly()方法選擇中斷, 改為處理其他事情,而synchronized關鍵字,執行緒需要一直等待下去。同樣的,tryLock()方法可以設定超時時間,用於在超時時間內一直獲取不到鎖時進行中斷。
  2. ReentrantLock可以實現公平鎖,而synchronized的鎖是非公平的。
  3. ReentrantLock擁有方便的方法用於獲取正在等待鎖的執行緒。
  4. ReentrantLock可以同時繫結多個Condition物件,而synchronized中,鎖物件的wait()和notify()或notifyAll()方法可以實現一個隱含的條件,如果要和多於一個條件關聯時,只能再加一個額外的鎖,而ReentrantLock只需要多次呼叫newCondition方法即可。

效能比較
在JDK1.6之前,ReentrantLock的效能要明顯優於synchronized,但是JDK1.6中加入了很多針對鎖的優化措施,synchronized和ReentrantLock的效能基本完全持平了。

ReentrantLock缺點
ReentrantLock的主要缺點是方法需要置於try-finally塊中,另外,開發人員需要負責獲取和釋放鎖,而開發人員常常忘記在finally中釋放鎖。