簡體   English   中英

順序運行Java線程

[英]Run Java Threads sequentially

您將如何依次執行三個線程? 例如。 線程1,線程2,線程3。 不可能將一個線程的引用傳遞給另一線程並從run()方法調用。

因此代碼應如下所示:

 Thread1.start();
 Thread2.start();
 Thread3.start();

和輸出應該

 Printing Thread1
 Printing Thread2
 Printing Thread3

這可以通過使用ThreadPoolExecutor並使用阻塞隊列來實現,但即使那樣也不是可以接受的答案。

您可以使用Executors.newSingleThreadExecutor() ,但嚴格來說,這僅啟動一個 Thread ,因此可能不是預期的解決方案。

僅使用Thread類的最簡單的解決方案:

Thread1.start();
Thread1.join();
Thread2.start();
Thread2.join();
Thread3.start();
Thread3.join();

(為了清楚起見,我省略了異常處理, Thread.join()可以拋出InterruptedException

最簡單的答案是

Thread1.run();
Thread2.run();
Thread3.run();

不切實際的問題所帶來的問題是,他們通常會得到一個信息不足的答案。 ;)

擁有線程的全部目的是同時運行它們。 如果您根本不這樣做,請不要使用線程。

你可能會這么說; 您不能調用run()方法,在這種情況下,您不能使用ThreadPoolExecutor,因為它會為您調用run()方法。 即多數民眾贊成提交()最終做什么。

編輯:結果是完全確定性的,因為涉及線程的事實是不可靠的。

static class PrintThread extends Thread {
    public PrintThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++)
            System.out.println(getName() + ": " + i);
    }
}

public static void main(String args[]) {
    Thread thread1 = new PrintThread("A");
    Thread thread2 = new PrintThread("B");
    Thread thread3 = new PrintThread("C");

    thread1.run();
    thread2.run();
    thread3.run();
}

版畫

A: 0
A: 1
.. deleted ..
C: 98
C: 99

如預期的那樣。

在java.util.concurrent包中使用ExecutorService 更精確地使用Executors.newSingleThreadExecutor();

可以使用ExecutorService順序執行線程。 查找以下示例。

public class SeqThread {

    public static void main(String[] arg) {
          new SeqThread().execute();
    }

    public void execute() {
        try {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        executor.submit(R);
        executor.submit(R2);
        executor.shutdown();

            executor.awaitTermination(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    Runnable R = new Runnable() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            for(int i=0;i<10;i++)
            {
                System.out.println("In Thread One "+i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    };

    Runnable R2 = new Runnable() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            for(int i=0;i<10;i++)
            {
                System.out.println("In Thread Two="+i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    };
}

由於這是一個面試問題,因此他們正在尋找特定的知識,而不是“這樣做顯然更好”的答案。 看來他們很可能會逐個解決方案,直到獲得所需的答案。

他們想看看您是否可以自己實現線程間通信,這很奇怪。 但是他們不希望您以簡單的方式做到這一點(可用線程引用)。 否則,您可以只執行thread.join()

因此,讓所有三個線程都獲取一些共享內存(同步的靜態類)。 讓每個線程檢查一個public static int nextThread() 成功比較它們是下一個線程后,他們應該執行工作,並使用要處理的下一個線程的值更新public static setNextThread(int value)

關鍵是要以線程安全的方式執行此操作; 但是,如果可以保證唯一的線程標識符,並確保沒有兩個線程具有相同的標識符,則可以(經過仔細的編碼)甚至可以做到不同步。

如果與調用這些線程的各種方式無關則從理論上講,他們應該使用獲取一個通用的sempahore ,並在完成打印后將其釋放。
JDK有一個內置的信號燈

強制線程以有序方式運行就像殺死了多線程這一概念,更像是單線程程序的子例程執行。 作為面試的問題,一切都很好。 這是不是用4個線程而是用50個線程測試邏輯的程序-

public class Outer {
    private Thread[] jobs;
    private String[] names;
    private int indx;

public Outer(int numOfThreads) {
    jobs = new Thread[numOfThreads];
    names = new String[numOfThreads];
    indx = numOfThreads - 1;
}

class Inner implements Runnable {
public void run() {
    while (true) {
       if (names[indx].equals(Thread.currentThread().getName())) {
          indx--;
          break;
       }
       else {
          try { Thread.sleep(20); } catch(InterruptedException ie) {}
       }
    }
    // now current thread will join behind the previous one..
    if (indx >= 0) try { jobs[indx].join(); } catch(InterruptedException ie) {}

    /***** YOUR ACTUAL CODE GOES FROM HERE *****/

    // at last check is it working ?
    System.out.println(Thread.currentThread().getName());
  }
}

public void f() {
    Inner target = new Inner();
    // initializing all threads..
    for (int i = 0; i < jobs.length; jobs[i++] = new Thread(target));
    for (int i = 0; i < names.length; names[i] = jobs[i++].getName());

    // checking name of threads..
    for (int i = 0; i < names.length; System.out.println(names[i++]));

    System.out.println();

    // now we start all threads..
    for (int i = 0; i < jobs.length; jobs[i++].start());
  }

public static void main(String[] args) {
    new Outer(50).f();               // testing logic not with 4 but 50 threads..
  }
}

您可以在此處找到所有內容: http : //download.oracle.com/javase/tutorial/essential/concurrency/index.html

尤其要閱讀有關線程之間的通知和同步的信息。

附言:請記住,即使通過面試,您仍然必須工作! :)

(好吧,我會給出一些提示:看起來像Object.wait()Object.notifyAll()這樣的方法的描述,這是最簡單但也非常有用的機制)

newSingleThreadExecutor。 單線程執行程序創建一個工作線程來處理任務,如果它意外死亡,則將其替換。 確保根據任務隊列強加的順序(FIFO,LIFO,優先級順序)順序處理任務。

我使用了基本的線程通信模型,它也可以更加簡化。 假設您有3個線程,其中一個正在打印0,第二個正在打印奇數,第三個正在打印偶數,例如01 02 03 04 05 ....

public class app{
        int status=0;
        public static void main(String[] args) throws InterruptedException{

            app obj = new app();
            Thread t1 = new Thread(new print(obj,0));
            Thread t2 = new Thread(new print(obj,1));
            Thread t3 = new Thread(new print(obj,2));
                t1.start();t2.start();t3.start();
            }

    }
    class print implements Runnable{
        app obj;
        int a;
        public print(app obj, int a) {
            this.obj=obj;
            this.a=a;
        }
        @Override
        public void run() {
            try{

                if(a==0){
                    synchronized(obj){
                    for (int i = 0; i < 21; i++) {
                        while(obj.status!=0 && obj.status!=3){
                            obj.wait();
                            } 

                        System.out.print(0);
                        if(obj.status==0)//even sets status to 0 so next one is odd
                            obj.status=1;
                        else//odd sets status to 3 so next one is even
                            obj.status=2;
                        obj.notifyAll();
                        }
                    }
                }
                    else if(a%2!=0){
                        synchronized (obj) {
                            for (int i = 0; i < 11; i++) {
                                while(obj.status!=1){
                                    obj.wait();
                                    } 

                                System.out.print(a);
                                a+=2;
                                obj.status=3;
                       //3 decides 0 came after odd, so next one           
                      //after zero is even
                                obj.notifyAll();
                            }
                        }
                    }
                    else{
                        synchronized (obj) {
                            for (int i = 0; i < 11; i++) {
                                while(obj.status!=2){
                                    obj.wait();
                                    } 

                                System.out.print(a);
                                a+=2;
                                obj.status=0;
                                obj.notifyAll();
                            }
                        }
                    }
                }




            catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                }
            }
        }

這可能是一個棘手的問題。 也許他們不想聽到針對此特定問題的解決方案,但希望您回溯到問題的根源並提出更好的解決方案。

我不確定我是否完全理解了這個問題,但是這似乎是我們想要按順序打印線程的情況。 一個示例是使用線程按如下順序打印值:

線程-0輸出:1

線程-1個輸出:2

線程-2輸出:3

線程-0輸出:4

線程-1輸出:5

線程-2輸出:6,依此類推。

如果這是必需的,則可以編寫n個線程的通用解決方案,其中每個線程將等待其輪換(使用將嘗試獲取鎖的公共對象)。

class ResourceLock {
    private volatile int currentThreadId;
    private final int totalThreads;

    public ResourceLock(int threadsCount) {
        this.currentThreadId = 0;
        this.totalThreads = threadsCount;
    }
    public void assignTokenToNextThread(int currentThreadNum) {
        this.currentThreadId = (currentThreadNum + 1) % totalThreads;
    }
    public int getCurrentThreadId() {
        return currentThreadId;
    }
}

現在,一個工作線程將完成其工作,並使用上述類的實例進行鎖定:

class Worker extends Thread {
    private final ResourceLock resourceLock;
    private final int threadId;                     // id of this thread
    private final AtomicInteger counter;            // counter shared by all threads, will print number in sequence.
    private volatile boolean running = true;        // flag to stop this thread when necessary
    public Worker(ResourceLock resourceLock, int threadNumber, AtomicInteger counter) {
        this.resourceLock = resourceLock;
        this.threadId = threadNumber;
        this.counter = counter;
    }
    @Override
    public void run() {
        while (running) {
            try {
                synchronized (resourceLock) {
                    while (resourceLock.getCurrentThreadId() != this.threadId) {
                        resourceLock.wait();
                    }
                    System.out.println("Thread:" + threadId + " value: " + counter.incrementAndGet());
                    Thread.sleep(1000);
                    resourceLock.assignTokenToNextThread(this.threadId);
                    resourceLock.notifyAll();
                }
            } catch (Exception e) {
                System.out.println("Exception: " + e);
            }
        }
    }
    public void shutdown() {
        running = false;
    }
}

可以測試為:

public static void main(String[] args) throws InterruptedException {
        final int threadsCount = 3;
        final ResourceLock lock = new ResourceLock(threadsCount);
        Worker[] threads = new Worker[threadsCount];
        final AtomicInteger counter = new AtomicInteger(0);
        for(int i=0; i<threadsCount; i++) {
            threads[i] = new Worker(lock, i, counter);
            threads[i].start();
        }
        Thread.sleep(20000);
        System.out.println("Will try to shutdown now...");
        for(Worker worker: threads) {
            worker.shutdown();
        }
    }
public static void main(String[] args)throws InterruptedException {

    MyRunnable r = new MyRunnable();
    Thread t1 = new Thread(r,"A");
    Thread t2 = new Thread(r,"B");
    Thread t3 = new Thread(r,"C");
    t1.start();
    Thread.sleep(1000);
    t2.start();
    Thread.sleep(1000);
    t3.start();



}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM