使用Java實現三個線程交替打印0-74


使用Java實現三個線程交替打印0-74

題目分析

 三個線程交替打印,即3個線程是按順序執行的。一個線程執行完之后,喚醒下一個線程,然后阻塞,等待被該線程的上一個線程喚醒。執行的順序是一個環裝的隊列 0->1->2->0 ....->0->1->2

實現思路

  由於三個線程一次只能有一個在打印數字,所以需要用一個鎖來進行同步。但是在打印時要保證順序就要求 一個線程打印完之后只能喚醒它的下一個線程,而不是喚醒所有的線程。這就要求給每一個線程都有一個自己的狀態來控制阻塞和喚醒。
  java 並發包中的鎖(實現了Lock接口的ReentrantLock、ReentrantReadWriteLock)有一個newCondition方法。調用該方法會返回與該鎖綁定Condition對象實例。當線程獲取鎖之后,調用Condition實例的await方法會自動釋放線程的鎖,當其他線程調用該Condition對象實例的signal方法后,該線程會自動嘗試獲取鎖。
   通過對Condition的分析可知,我們只要對三個線程生成三個Condition對象。當一個線程打印一個數字之后就調用下一個線程的Condition對象的signal方法喚醒下一個線程,然后調用自己的Condition的await線程進入等待狀態。這樣就實現了線程執行順序的控制。由於線程的執行是一個環形的隊列,我們用一個數組存放每個線程的Condition對象,通過對下標加一然后取模來實現環形隊列。

代碼

package com.test.concurrent.alternatingprint;

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


public class PrintNumber extends Thread {
    /**
     * 多個線程共享這一個sequence數據
     */
    private static int sequence=0;

    private static final int SEQUENCE_END =75;

    private Integer id;
    private ReentrantLock lock;
    private Condition[] conditions;



    private PrintNumber(Integer id,  ReentrantLock lock, Condition[] conditions) {
        this.id = id;
        this.setName("thread" + id);
        this.lock = lock;
        this.conditions = conditions;
    }

    @Override
    public void run() {
        while (sequence >= 0 && sequence < SEQUENCE_END) {
            lock.lock();
            try {
                //對序號取模,如果不等於當前線程的id,則先喚醒其他線程,然后當前線程進入等待狀態
                while (sequence % conditions.length != id) {
                    conditions[(id + 1) % conditions.length].signal();
                    conditions[id].await();
                }
                System.out.println(Thread.currentThread().getName() + " " + sequence);
                //序號加1
                sequence = sequence + 1;
                //喚醒當前線程的下一個線程
                conditions[(id + 1) % conditions.length].signal();
                //當前線程進入等待狀態
                conditions[id].await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //將釋放鎖的操作放到finally代碼塊中,保證鎖一定會釋放
                lock.unlock();
            }
        }
        //數字打印完畢,線程結束前喚醒其余的線程,讓其他線程也可以結束
        end();
    }

    private void end() {
        lock.lock();
        conditions[(id + 1) % conditions.length].signal();
        conditions[(id + 2) % conditions.length].signal();
        lock.unlock();
    }

    public static void main(String[] args) {
        int threadCount = 3;
        ReentrantLock lock = new ReentrantLock();
        Condition[] conditions = new Condition[threadCount];
        for (int i = 0; i < threadCount; i++) {
            conditions[i] = lock.newCondition();
        }
        PrintNumber[] printNumbers = new PrintNumber[threadCount];
        for (int i = 0; i < threadCount; i++) {
            PrintNumber p = new PrintNumber(i, lock, conditions);
            printNumbers[i] = p;
        }
        for (PrintNumber printNumber : printNumbers) {
            printNumber.start();
        }
    }

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM