我如何按照实例化的顺序订购线程。如何使下面的程序按顺序打印数字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();
}
}
}
答案 0 :(得分:12)
听起来你想要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();
}
}
}
答案 1 :(得分:7)
“我实际上有一些我希望并行执行的部分,然后一旦生成结果,我想按特定顺序合并结果。”谢谢,这澄清了你的要求。
您可以一次性运行它们,但重要的是在线程完成计算时按顺序获取结果。要么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());
}
}
}
答案 2 :(得分:4)
简单地说,线程的安排是不确定的。
死域 - 请勿点击 http://www.janeg.ca/scjp/threads/scheduling.html
WaybackMachine version of the above page
更长的答案是,如果要执行此操作,则需要手动等待每个线程完成其工作,然后再允许其他线程运行。请注意,以这种方式,所有线程仍将交错,但在您批准之前它们将无法完成任何工作。看一下同步保留字。
答案 3 :(得分:3)
你可以链接它们 - 也就是说,让第一个开始第二个,第二个开始第三个,等等。它们不会真正同时运行,除了每个启动时有点重叠。
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();
}
}
答案 4 :(得分:2)
这是一种方法,无需拥有等待每个结果的主线程。相反,让工作线程共享一个对结果进行排序的对象。
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);
}
}
答案 5 :(得分:1)
如果你需要那种细粒度的控件,你不应该使用线程,而是考虑使用一个合适的Executor with Callables或Runnables。请参阅Executors类以获得广泛的选择。
答案 6 :(得分:1)
一个简单的解决方案是使用数组A
锁(每个线程一个锁)。当线程i
开始执行时,它会获取其关联的锁A[i]
。当它准备好合并其结果时,它会释放其锁A[i]
并等待锁A[0], A[1], ..., A[i - 1]
被释放;然后它合并结果。
(在此上下文中,线程i
表示i
- 已启动的线程)
我不知道在Java中使用哪些类,但它必须易于实现。您可以开始阅读this。
如果您有更多问题,请随时提出。
答案 7 :(得分:1)
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();
}
答案 8 :(得分:0)
使用信号量可以非常容易地实现对线程执行顺序的控制。附带的代码基于Schildt的Java书籍(完整的参考文献......)中提出的想法。 //基于以下提出的想法: // Schildt H。:Java.The.Complete.Reference.9th.Edition。
void Logger::init(Logger::severity_level level)
{
boost::log::add_common_attributes();
boost::shared_ptr<boost::log::core> core = boost::log::core::get();
core->set_exception_handler(boost::log::make_exception_suppressor()); //disable exception. in case file write permission problem
core->get()->add_global_attribute("Scope", boost::log::attributes::named_scope());
core->get()->add_global_attribute("File", boost::log::attributes::mutable_constant<std::string>(""));
core->get()->add_global_attribute("Line", boost::log::attributes::mutable_constant<int>(0));
//core->set_filter(boost::log::expressions::attr<Logger::severity_level>("Severity") >= level);
#ifdef _DEBUG
{
typedef boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend> cout_sink;
boost::shared_ptr<cout_sink> sink = boost::make_shared<cout_sink>();
boost::shared_ptr<std::ostream> stream(&std::clog, boost::null_deleter());
sink->locked_backend()->add_stream(stream);
sink->set_filter(channel == main_channel && boost::log::expressions::attr<Logger::severity_level>("Severity") >= level);
core->add_sink(sink);
}
boost::log::add_file_log(
boost::log::keywords::filter = channel == main_channel && boost::log::expressions::attr<Logger::severity_level>("Severity") >= level,
//boost::log::keywords::filter = channel == main_channel,
boost::log::keywords::file_name = "./log/%Y%m%d.log",
boost::log::keywords::auto_flush = true,
boost::log::keywords::open_mode = (std::ios::out | std::ios::app),
boost::log::keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0),
//boost::log::keywords::format = "[%TimeStamp%] [%__LINE__%] (%LineID%) {%ThreadID%}: %Message%"
boost::log::keywords::format = (
boost::log::expressions::stream
<< "[" << boost::log::expressions::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d_%H:%M:%S.%f") << "] "
<< "(" << boost::log::expressions::attr<unsigned int>("LineID") << ") "
<< "(" << boost::log::expressions::attr<boost::log::aux::thread::id>("ThreadID") << ") "
<< '[' << boost::log::expressions::attr<std::string>("File") << ":"
<< boost::log::expressions::attr<int>("Line") << "] "
<< boost::log::expressions::smessage
)
);
}
答案 9 :(得分:0)
可以不使用synchronized关键字并在 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
}
}
}
}
}
}
以下是github链接,它有一个自述文件,详细解释了它是如何发生的。 https://github.com/sankar4git/volatile_thread_ordering