Java 排序线程按照它们的创建/启动顺序运行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3741765/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ordering threads to run in the order they were created/started
提问by keshav84
How can i order threads in the order they were instantiated.e.g. how can i make the below program print the numbers 1...10 in order.
我如何按照线程被实例化的顺序订购线程。例如,我如何让下面的程序按顺序打印数字 1...10。
public class ThreadOrdering {
public static void main(String[] args) {
class MyRunnable implements Runnable{
private final int threadnumber;
MyRunnable(int threadnumber){
this.threadnumber = threadnumber;
}
public void run() {
System.out.println(threadnumber);
}
}
for(int i=1; i<=10; i++){
new Thread(new MyRunnable(i)).start();
}
}
}
采纳答案by finnw
Sounds like you want ExecutorService.invokeAll
, which will return results from worker threads in a fixed order, even though they may be scheduled in arbitrary order:
听起来像你想要的ExecutorService.invokeAll
,它将以固定顺序从工作线程返回结果,即使它们可能以任意顺序调度:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadOrdering {
static int NUM_THREADS = 10;
public static void main(String[] args) {
ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS);
class MyCallable implements Callable<Integer> {
private final int threadnumber;
MyCallable(int threadnumber){
this.threadnumber = threadnumber;
}
public Integer call() {
System.out.println("Running thread #" + threadnumber);
return threadnumber;
}
}
List<Callable<Integer>> callables =
new ArrayList<Callable<Integer>>();
for(int i=1; i<=NUM_THREADS; i++) {
callables.add(new MyCallable(i));
}
try {
List<Future<Integer>> results =
exec.invokeAll(callables);
for(Future<Integer> result: results) {
System.out.println("Got result of thread #" + result.get());
}
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (ExecutionException ex) {
ex.printStackTrace();
} finally {
exec.shutdownNow();
}
}
}
回答by San Jacinto
Simply put, the scheduling of threads is indeterminate.
简单地说,线程的调度是不确定的。
Dead domain - do not clickhttp://www.janeg.ca/scjp/threads/scheduling.html
死域 - 不要点击http://www.janeg.ca/scjp/threads/scheduling.html
WaybackMachine version of the above page
The longer answer is that if you want to do this, you'll need to manually wait for each thread to complete its work before you allow another to run. Note that in this fashion, all the threads will still interleave but they won't accomplish any work until you give the go-ahead. Have a look at the synchronize reserved word.
更长的答案是,如果您想这样做,您需要手动等待每个线程完成其工作,然后再允许另一个线程运行。请注意,以这种方式,所有线程仍将交错,但在您同意之前它们不会完成任何工作。看看同步保留字。
回答by Thorbj?rn Ravn Andersen
If you need that fine-grained control, you should not use threads but instead look into using a suitable Executor with Callables or Runnables. See the Executors class for a wide selection.
如果您需要细粒度控制,则不应使用线程,而应考虑使用合适的 Executor 和 Callables 或 Runnables。请参阅 Executors 类以获得广泛的选择。
回答by Peter DeWeese
You can chain them – that is, have the first one start the second, the second start the third, etc. They won't really be running at the same time except for a bit of overlap when each one is started.
你可以链接它们——也就是说,让第一个启动第二个,第二个启动第三个,等等。它们不会真正同时运行,除了在每个启动时有一点重叠。
public class ThreadOrdering
{
public static void main(String[] args)
{
MyRunnable[] threads = new MyRunnable[10];//index 0 represents thread 1;
for(int i=1; i<=10; i++)
threads[i] = new MyRunnable(i, threads);
new Thread(threads[0].start);
}
}
public class MyRunnable extends Runnable
{
int threadNumber;
MyRunnable[] threads;
public MyRunnable(int threadNumber, MyRunnable[] threads)
{
this.threadnumber = threadnumber;
this.threads = threads;
}
public void run()
{
System.out.println(threadnumber);
if(threadnumber!=10)
new Thread(threadnumber).start();
}
}
回答by jbindel
"I actually have some parts that i want to execute in parallel, and then once the results are generated, I want to merge the results in certain order." Thanks, this clarifies what you're asking.
“我实际上有一些我想并行执行的部分,然后一旦生成结果,我想以一定的顺序合并结果。” 谢谢,这说明了你在问什么。
You can run them all at once, but the important thing is to get their results in order when the threads finish their computation. Either Thread#join()
them in the order in which you want to get their results, or just Thread#join()
them all and then iterate through them to get their results.
您可以同时运行它们,但重要的是在线程完成计算时按顺序获取它们的结果。要么Thread#join()
按照您想要获得结果的顺序进行处理,要么只是Thread#join()
全部执行,然后遍历它们以获得结果。
// Joins the threads back to the main thread in the order we want their results.
public class ThreadOrdering {
private class MyWorker extends Thread {
final int input;
int result;
MyWorker(final int input) {
this.input = input;
}
@Override
public void run() {
this.result = input; // Or some other computation.
}
int getResult() { return result; }
}
public static void main(String[] args) throws InterruptedException {
MyWorker[] workers = new MyWorker[10];
for(int i=1; i<=10; i++) {
workers[i] = new MyWorker(i);
workers[i].start();
}
// Assume it may take a while to do the real computation in the threads.
for (MyWorker worker : workers) {
// This can throw InterruptedException, but we're just passing that.
worker.join();
System.out.println(worker.getResult());
}
}
}
回答by yassin
A simple solution would be to use an array A
of locks (one lock per thread). When thread i
begins its executions, it acquires its associated lock A[i]
. When it's ready to merge its results, it releases its lock A[i]
and waits for locks A[0], A[1], ..., A[i - 1]
to be released; then it merges the results.
一个简单的解决方案是使用一组A
锁(每个线程一个锁)。当线程i
开始执行时,它获取其关联的锁A[i]
。当它准备好合并它的结果时,它释放它的锁A[i]
并等待锁A[0], A[1], ..., A[i - 1]
被释放;然后合并结果。
(In this context, thread i
means the i
-th launched thread)
(在这种情况下,线程i
是指第i
-th 个启动的线程)
I don't know what classes to use in Java, but it must be easy to implement. You can begin reading this.
我不知道在 Java 中使用哪些类,但它必须易于实现。您可以开始阅读本文。
If you have more questions, feel free to ask.
如果您有更多问题,请随时提问。
回答by Tom Anderson
Here's a way to do it without having a master thread that waits for each result. Instead, have the worker threads share an object which orders the results.
这是一种无需主线程等待每个结果的方法。相反,让工作线程共享一个对结果进行排序的对象。
import java.util.*;
public class OrderThreads {
public static void main(String... args) {
Results results = new Results();
new Thread(new Task(0, "red", results)).start();
new Thread(new Task(1, "orange", results)).start();
new Thread(new Task(2, "yellow", results)).start();
new Thread(new Task(3, "green", results)).start();
new Thread(new Task(4, "blue", results)).start();
new Thread(new Task(5, "indigo", results)).start();
new Thread(new Task(6, "violet", results)).start();
}
}
class Results {
private List<String> results = new ArrayList<String>();
private int i = 0;
public synchronized void submit(int order, String result) {
while (results.size() <= order) results.add(null);
results.set(order, result);
while ((i < results.size()) && (results.get(i) != null)) {
System.out.println("result delivered: " + i + " " + results.get(i));
++i;
}
}
}
class Task implements Runnable {
private final int order;
private final String result;
private final Results results;
public Task(int order, String result, Results results) {
this.order = order;
this.result = result;
this.results = results;
}
public void run() {
try {
Thread.sleep(Math.abs(result.hashCode() % 1000)); // simulate a long-running computation
}
catch (InterruptedException e) {} // you'd want to think about what to do if interrupted
System.out.println("task finished: " + order + " " + result);
results.submit(order, result);
}
}
回答by Diana
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();
}
回答by Marek
Control of thread execution order may be implemented quite easily with the semaphores. The code attached is based on the ideas presented in Schildt's book on Java (The complete reference....). // Based on the ideas presented in: // Schildt H.: Java.The.Complete.Reference.9th.Edition.
使用信号量可以很容易地实现对线程执行顺序的控制。所附代码基于 Schildt 关于 Java 的书(完整参考....)中提出的想法。// 基于以下观点: // Schildt H.: Java.The.Complete.Reference.9th.Edition.
import java.util.concurrent.Semaphore;
class Manager {
int n;
// Initially red on semaphores 2&3; green semaphore 1.
static Semaphore SemFirst = new Semaphore(1);
static Semaphore SemSecond = new Semaphore(0);
static Semaphore SemThird = new Semaphore(0);
void firstAction () {
try {
SemFirst.acquire();
} catch(InterruptedException e) {
System.out.println("Exception InterruptedException catched");
}
System.out.println("First: " );
System.out.println("-----> 111");
SemSecond.release();
}
void secondAction() {
try{
SemSecond.acquire();
} catch(InterruptedException e) {
System.out.println("Exception InterruptedException catched");
}
System.out.println("Second: ");
System.out.println("-----> 222");
SemThird.release();
}
void thirdAction() {
try{
SemThird.acquire();
} catch(InterruptedException e) {
System.out.println("Exception InterruptedException catched");
}
System.out.println("Third: ");
System.out.println("-----> 333");
SemFirst.release();
}
}
class Thread1 implements Runnable {
Manager q;
Thread1(Manager q) {
this.q = q;
new Thread(this, "Thread1").start();
}
public void run() {
q.firstAction();
}
}
class Thread2 implements Runnable {
Manager q;
Thread2(Manager q) {
this.q = q;
new Thread(this, "Thread2").start();
}
public void run() {
q.secondAction();
}
}
class Thread3 implements Runnable {
Manager q;
Thread3(Manager q) {
this.q = q;
new Thread(this, "Thread3").start();
}
public void run() {
q.thirdAction();
}
}
class ThreadOrder {
public static void main(String args[]) {
Manager q = new Manager();
new Thread3(q);
new Thread2(q);
new Thread1(q);
}
}
回答by sankar banerjee
This can be done without using synchronized keywordand with the help of volatilekeyword. Following is the code.
这可以在不使用同步关键字和volatile关键字的帮助下完成。以下是代码。
package threadOrderingVolatile;
public class Solution {
static volatile int counter = 0;
static int print = 1;
static char c = 'A';
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread[] ths = new Thread[4];
for (int i = 0; i < ths.length; i++) {
ths[i] = new Thread(new MyRunnable(i, ths.length));
ths[i].start();
}
}
static class MyRunnable implements Runnable {
final int thID;
final int total;
public MyRunnable(int id, int total) {
thID = id;
this.total = total;
}
@Override
public void run() {
while(true) {
if (thID == (counter%total)) {
System.out.println("thread " + thID + " prints " + c);
if(c=='Z'){
c='A';
}else{
c=(char)((int)c+1);
}
System.out.println("thread " + thID + " prints " + print++);
counter++;
} else {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// log it
}
}
}
}
}
}
Following is the github link which has a readme, that gives detailed explanation about how it happens. https://github.com/sankar4git/volatile_thread_ordering
以下是包含自述文件的 github 链接,其中详细解释了它是如何发生的。 https://github.com/sankar4git/volatile_thread_ordering