按顺序运行Java线程

问题描述 投票:9回答:13

你将如何顺序执行三个线程?例如。 Thread1,Thread2,Thread3。无法将一个Thread的引用传递给另一个Thread并从run()方法调用。

所以代码应该是这样的:

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

应该是

 Printing Thread1
 Printing Thread2
 Printing Thread3

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

java multithreading concurrency java.util.concurrent
13个回答
10
投票

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


0
投票

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


0
投票

我使用了基本的线程通信模型,它也可以更简化。假设你有3个线程,一个是打印0,第二个是打印奇数,第三个是打印偶数liker这个01 02 03 04 05 ....

Object.notifyAll()

0
投票

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

线程 - 0输出:1

线程 - 1输出:2

线程 - 2输出:3

线程 - 0输出:4

线程 - 1输出:5

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

如果这是要求,则可以编写n个线程的通用解决方案,其中每个线程将等待轮到它(使用它将尝试获取锁的公共对象)。

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

现在一个工作线程将完成它的工作,并使用上面的类的实例来锁定目的:

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

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

15
投票

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

使用qazxsw poi类的最简单的解决方案:

Thread

(为了清楚起见,我省略了异常处理,Thread1.start(); Thread1.join(); Thread2.start(); Thread2.join(); Thread3.start(); Thread3.join(); 可以抛出Thread.join()


11
投票

最简单的答案是

InterruptedException

不切实际的问题是他们经常有一个无法解释的答案。 ;)

拥有线程的重点是同时运行它们。如果您根本不这样做,请不要使用线程。

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

编辑:结果是完全确定的,因为有一个涉及的线程是不可靠的。

Thread1.run();
Thread2.run();
Thread3.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();
}

正如所料。


4
投票

由于这是一个面试问题,他们正在寻找具体的知识,而不是“以这种方式做到这一点明显更好”的答案。似乎他们可能会在解决方案之后找出解决方案,直到他们得到他们想要的答案。

他们想知道你是否可以自己实现线程间通信。但是他们不希望你这么简单(可用的线程参考)。否则,你可以做A: 0 A: 1 .. deleted .. C: 98 C: 99

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

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


4
投票

如果它与调用这些线程的各种方式无关,理论上,它们应该使用public static setNextThread(int value),并在完成打印时释放它。 JDK有一个acquire a common sempahore


4
投票

可以使用ExecutorService按顺序执行线程。找到下面的例子。

inbuilt semaphore

2
投票

强制线程以有序的方式运行就像杀死多线程的概念一样,它更像是单线程程序的子例程执行。作为面试问题所以一切都好。这是一个用4个而不是50个线程测试逻辑的程序 -

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

1
投票

你可以找到那里的一切: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.htmlObject.wait()这样的方法的描述它是最简单但也非常有用的机制)


1
投票

newSingleThreadExecutor。单线程执行程序创建一个工作线程来处理任务,如果它意外死亡则替换它。保证任务按照任务队列(FIFO,LIFO,优先级顺序)强加的顺序依次处理。

© www.soinside.com 2019 - 2024. All rights reserved.