按顺序运行 Java 线程

发布于 2024-10-27 12:53:14 字数 327 浏览 2 评论 0原文

您将如何顺序执行三个线程?例如。线程 1、线程 2、线程 3。无法将一个线程的引用传递给另一个线程并从 run() 方法调用。

所以代码应该是这样的:

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

输出应该是

 Printing Thread1
 Printing Thread2
 Printing Thread3

这可以通过使用 ThreadPoolExecutor 和使用阻塞队列来实现,但即使这也不是一个可接受的答案。

How will you execute Three threads sequentially? For eg. Thread1, Thread2, Thread3. It is not possible to pass the reference of one Thread to the other and invoke from the run() method.

So code should be like this:

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

and out put should be

 Printing Thread1
 Printing Thread2
 Printing Thread3

This can be possible by using ThreadPoolExecutor and using a blocking queue but even that is not an acceptable answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

分開簡單 2024-11-03 12:53:16

由于这是一个面试问题,他们正在寻找具体的知识,而不是“嗯,这样做显然更好”的答案。他们似乎还可能会提出一个又一个的解决方案,直到得到他们想要的答案。

他们很可能想看看您是否可以自己实现线程间通信。但他们不希望您以简单的方式做到这一点(可用线程参考)。否则,您可以只执行thread.join()

因此,所有三个线程都获取一些共享内存(同步静态类)。让每个线程检查一个public static int nextThread()。成功比较它们是下一个线程后,它们应该完成工作并用要处理的下一个线程的值更新 public static setNextThread(int value)

关键是以线程安全的方式做到这一点;但是,如果您可以保证唯一的线程标识符并确保没有两个线程具有相同的标识符,您甚至可以(通过仔细编码)在不同步的情况下做到这一点。

Since this is an interview question, they're looking for specific knowledge, not a "well it's obviously better to do it this way" answer. It also seems that they'll likely strike out solution after solution until they get the answer they want.

Odds are they want to see if you can implement inter-thread communications yourself. But they don't want you to do it the easy way (thread references available). Otherwise, you could just do thread.join().

So have all three threads grab some bit of shared memory (synchronized static class). Have each thread check a public static int nextThread(). Upon successful comparison that they are the next thread, they should do their work and update public static setNextThread(int value) with the value of the next thread to be processed.

The key is to do this in a thread-safe manner; however, if you can guarantee unique thread identifiers and ensure that no two threads have the same identifier, you can (with careful coding) even manage to do this without synchronization.

爱你不解释 2024-11-03 12:53:16

使用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();
                }
            }
        }
    };
}

Threads can be executed sequentially by using ExecutorService. Find below example.

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();
                }
            }
        }
    };
}
青芜 2024-11-03 12:53:16

如果不是涉及到调用这些线程的各种方式,理论上来说,他们应该使用 获取一个共同的信号量,打印完成后释放。
JDK 有一个 内置信号量

If it were not related to various ways of invoking these threads, theoretically, they should use acquire a common sempahore, and release it when done printing.
JDK has an inbuilt semaphore.

猫瑾少女 2024-11-03 12:53:16

强制线程以有序的方式运行就像扼杀了这个概念
多线程,它更像是单线程程序的子程序执行。由于它的面试问题所以一切都OK。这是测试逻辑的程序,不是使用 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..
  }
}

Forcing threads to run in ordered manner is like killing the very concept of
multithreading, its more like single threaded program' sub-routine execution. As its interview question so everything is OK. Here is the program that test the logic not with 4 but 50 threads-

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..
  }
}
屌丝范 2024-11-03 12:53:16

您可以在那里找到所有内容: http://download.oracle.com/javase /tutorial/essential/concurrency/index.html

特别阅读有关线程之间的通知和同步的内容。

PS 请记住,即使您通过了面试,您仍然必须工作! :)

(好吧,我会给出一些提示:看看 Object.wait()Object.notifyAll() 等方法的描述,它是最简单的,但也非常有用的机制)

You can find everything there: http://download.oracle.com/javase/tutorial/essential/concurrency/index.html

Especially read about notifications and synchronization between threads.

P.S. And remember, even if you pass the interview you'll still had to work! :)

(Ok, I'll give some hints: look the description of such methods as Object.wait() and Object.notifyAll() it is the simpliest but also very usefull mechanism)

没有伤那来痛 2024-11-03 12:53:16

新的单线程执行器。单线程执行器创建一个工作线程来处理任务,如果它意外终止则替换它。任务保证按照任务队列规定的顺序(先进先出、后进先出、优先级顺序)顺序处理。

newSingleThreadExecutor. A single-threaded executor creates a single worker thread to process tasks, replacing it if it dies unexpectedly. Tasks are guaranteed to be processed sequentially according to the order imposed by the task queue (FIFO, LIFO, priority order).

有深☉意 2024-11-03 12:53:16

这可能是一个棘手的问题。也许他们不想听到这个特定问题的解决方案,而是希望你回溯到问题的根源并提出更好的解决方案。

This could be a trick question. Maybe they don't want to hear the solution to this specific problem but want you to back track to the source of the problem and come up with a better solution.

顾北清歌寒 2024-11-03 12:53:16

我使用了基本的线程通信模型,它也可以更加简化。假设你有 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();
                }
            }
        }

I've used basic thread communication model and it could be more simplified as well. Let's say you have 3 threads, one is printing 0, second one is printing odd number and third one is printing even number liker this
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();
                }
            }
        }
空城之時有危險 2024-11-03 12:53:16

我不确定我是否完全理解这个问题,但这似乎是我们想要按顺序打印线程的情况。一个示例是使用线程按如下顺序打印值:

线程 - 0 输出:1

线程 - 1 输出:2

线程 - 2 输出:3

线程 - 0 输出:4

线程 - 1 个输出:5

线程 - 2 输出:6 等等..

如果这是要求,则通用解决方案可以编写 for 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();
        }
    }

I am not sure if I understood the question completely but this seems like a situation where we want to print the threads in sequence. One example is to print the value using threads in a sequence like:

Thread - 0 output: 1

Thread - 1 output: 2

Thread - 2 output: 3

Thread - 0 output: 4

Thread - 1 output: 5

Thread - 2 output: 6 and so on..

If this is the requirement then a generic solution for n threads can be written where each thread will wait for its turn (using common object on which it will try to acquire lock).

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;
    }
}

Now a worker thread will do its job and use the instance of above class for locking purpose:

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;
    }
}

And this can be tested as:

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();
        }
    }
伤痕我心 2024-11-03 12:53:16
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();



}
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();



}
淡紫姑娘! 2024-11-03 12:53:15

您可以使用 Executors.newSingleThreadExecutor() ,但严格来说,这仅启动 一个 Thread,因此可能不是预期的解决方案。

仅使用 Thread 类的最简单解决方案:(

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

为了清楚起见,我省略了异常处理,Thread.join() 可以抛出 InterruptedException)

You could use Executors.newSingleThreadExecutor(), but strictly speaking this launches only one Thread, so may not be expected solution.

The simpliest solution using just Thread class:

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

(I omitted exception handling for clarity, Thread.join() can throw InterruptedException)

白日梦 2024-11-03 12:53:15

使用 java.util.concurrent 包中的 ExecutorService 。更准确地说,使用 Executors.newSingleThreadExecutor();

Use ExecutorService in java.util.concurrent package. More precisely use Executors.newSingleThreadExecutor();

半山落雨半山空 2024-11-03 12:53:15

最简单的答案是

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

不切实际的问题的问题是它们通常会得到无信息的答案。 ;)

拥有线程的全部意义在于同时运行它们。如果您根本不这样做,请不要使用线程。

你可能会这么说;你不能调用 run() 方法,在这种情况下你不能使用 ThreadPoolExecutor,因为它会为你调用 run() 方法。即,这就是submit() 最终所做的事情。

编辑:结果是完全确定的,因为涉及线程的事实是无关的。

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

按预期

The simplest answer is

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

The problem with unrealistic questions is they often have an uninformative answer. ;)

The whole point of having threads is to run them concurrently. If you are not doing that at all, don't use threads.

You might say that; you cannot call the run() method, in which case you cannot use ThreadPoolExecutor because it calls the run() method for you. i.e. thats what submit() eventually does.

EDIT: The results are completely deterministic, becaus ethe fact that there is a Thread involved is irrelivent.

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();
}

Prints

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

as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文