Java 如何让线程以有序的顺序运行?

Java 如何让线程以有序的顺序运行?,java,Java,我正在学习Java线程,希望我的代码按顺序输出线程0-9。我使用了synchronized关键字,但没有得到预期的结果 我应该如何更正我的代码 公共类MyThread扩展线程{ 私有静态最终int threadMax=10; 私有静态int运行计数=0; public void printThread(){ 已同步(此){ while(runCount++

我正在学习Java线程,希望我的代码按顺序输出线程0-9。我使用了synchronized关键字,但没有得到预期的结果

我应该如何更正我的代码

公共类MyThread扩展线程{
私有静态最终int threadMax=10;
私有静态int运行计数=0;
public void printThread(){
已同步(此){
while(runCount++<100){
System.out.println(runCount+“:”+Thread.currentThread().getName());
试一试{
睡眠(1000);
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
}
}
公开募捐{
printThread();
}
公共静态void main(字符串[]args){
对于(int i=0;i
您正在同步线程的上下文,每个线程的上下文都不同。您应该将所有不同线程的任何公共对象放入
synchronized
键中。这不会让他们在任何特定的时间内运行,只是等待彼此结束。 如果要出于任何目的测试
synchronized
关键字,可以传递构造函数a公共变量,并在每个线程中使用它:

public class MyThread extends Thread {

private static final int threadMax = 10;
private static int runCount = 0;
private Object test; //Object pointing main method

public MyThread(Object test){
 this.test = test; //This won't copy values as it is an object and not a number, string...
}

public void printThread() {
    synchronized (test) { //Same object for all threads
        while (runCount++ < 100) {
            System.out.println(runCount + ": " + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

public void run() {

    printThread();

}

public static void main(String[] args) {

    Object test; //common object
    for (int i = 0; i < threadMax; i++) {
        new MyThread(test).start();
    }

}
公共类MyThread扩展线程{
私有静态最终int threadMax=10;
私有静态int运行计数=0;
私有对象测试;//对象指向主方法
公共数据读取(对象测试){
this.test=test;//这不会复制值,因为它是对象而不是数字、字符串。。。
}
public void printThread(){
已同步(测试){//所有线程的同一对象
while(runCount++<100){
System.out.println(runCount+“:”+Thread.currentThread().getName());
试一试{
睡眠(1000);
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
}
}
公开募捐{
printThread();
}
公共静态void main(字符串[]args){
对象测试;//公共对象
对于(int i=0;i
}

如果您还想让它们按顺序启动,则应“同步”循环生成
wait
notify
调用


无论如何,多线程的要点是让多个线程在“相同”的时间运行,而不是按顺序运行,因为这与线性执行是一样的。

它不会像每次创建新的
MyThread
对象并在该新对象上同步时那样工作。因此,您创建的每个
线程将在不同对象上获得一个锁。因此,您应该传递一个公共对象来获取锁,如下所示

class MyThread extends Thread {

    private static int runCount = 0;

    Object lock;

    public MyThread(Object lock) {
        this.lock = lock;
    }

    public void printThread() {
        synchronized (lock) {
           // your code here
        }

    }

 //.........
}
然后像这样称呼它:

Object lock = new Object();
for (int i = 0; i < threadMax; i++) {
    new MyThread(lock).start();
}
并将线程称为:

    Object lock = new Object();
    for (int i = 0; i < 10; i++) {
        new MyThread(lock, i).start();
    }
对象锁=新对象();
对于(int i=0;i<10;i++){
新的MyThread(lock,i).start();
}

您有几个任务要委托给线程,但要按顺序执行

正如其他人所指出的,wait¬ify可以帮助您实现这一点:等到第n次完成,然后通知下一次。但是,如果在
printThread
方法中等待/通知,因为所有线程都在同一个锁上同时等待,因此无法保证下一个线程将是N+1个线程。所以你可能有

1: thread-1
...
10: thread-1
11: thread-5
...
20: thread-5
21: thread-2
...
如果这对你合适,你就完了。但是,在您特别希望对线程进行排序的情况下,您需要的是一个等待队列(FIFO:先进先出)

要实现这一点,您可以使用awesome
ExecutorService
。但是,请注意,它们对您隐藏了
线程
s,选择该解决方案不应以事先了解它们的基础知识为代价

ExecutorService
是一个非常方便的类,它可以接收任务(以Runnable的形式,见下文),并在单独的线程中执行任务

这里,我使用的是一个
SingleThreadExecutor
,它按顺序执行提交的任务。因此,您所要做的就是使用任务作为参数调用它的
execute
方法,
ExecutorService
将以正确的顺序依次运行它们

以下是您可以通过一些注释完成的操作:

public class ThreadRunner {

    // Note : Constants are usually all uppercase in Java
    private static final int MAX_THREADS = 10;

    private final int threadName;

    public ThreadRunner(int threadName) {
        this.threadName = threadName;
    }

    public void printThread() {
        // Note: For loops are better than while when you already know the number of iterations
        for (int runCount = 0; runCount < 10; runCount++) {
            System.out.println(runCount + "th run from thread " + threadName);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        for (int i = 0; i < MAX_THREADS; i++) {
            int threadName = i + 1;
            // Submit a task to the executor
            executorService.execute(() -> new ThreadRunner(threadName).printThread());
        }

        // Nicely ask for the executor to shutdown.
        // Then wait for already submitted tasks to terminate.
        executorService.shutdown();
        try {
            executorService.awaitTermination(120, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
您正在创建一个新的
线程
,根据您的Java版本,使用lambda或匿名类将
可运行
作为构造函数参数传递

Runnable
只是将要执行的代码的一部分(在本例中,由线程执行)

同样适用于
ExecutorService
,它是
execute
方法。该方法采用我通过lambdas创建的
Runnable

线程间共享
静态
计数器
您的行
private static int runCount=0
是一个静态字段,这意味着它由类的所有实例共享
MyThread
。当您在一个线程中增加它时,所有线程都将读取(和写入)同一个变量

如果您的线程按顺序运行,第一个线程将执行100次迭代,然后当第二个线程启动时,
runCount
已经达到100,并且您不会进入while循环。如果这不是有意的,那么在测试代码时可能会产生混乱

基于您在评论中的预期输出,我相信您希望您的线程每个都执行10次迭代,而不是共享100次迭代的池,并设法让每个线程只执行10次

线程名称属于每个
ThreadRunner
这里的小细节:之前,您创建了10个线程。在这里,
Exec
public class ThreadRunner {

    // Note : Constants are usually all uppercase in Java
    private static final int MAX_THREADS = 10;

    private final int threadName;

    public ThreadRunner(int threadName) {
        this.threadName = threadName;
    }

    public void printThread() {
        // Note: For loops are better than while when you already know the number of iterations
        for (int runCount = 0; runCount < 10; runCount++) {
            System.out.println(runCount + "th run from thread " + threadName);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        for (int i = 0; i < MAX_THREADS; i++) {
            int threadName = i + 1;
            // Submit a task to the executor
            executorService.execute(() -> new ThreadRunner(threadName).printThread());
        }

        // Nicely ask for the executor to shutdown.
        // Then wait for already submitted tasks to terminate.
        executorService.shutdown();
        try {
            executorService.awaitTermination(120, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
    public static void main(String[] args) {
        // Using Java 1.8+ lambda
        Thread lambdaThread = new Thread(() -> System.out.println("Hello from a lambda in a Thread"));
        lambdaThread.start();

        // Using an anonymous class for java <1.8
        Thread anonClassThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello from an anonymous class in a Thread");
            }
        });
        anonClassThread.start();
    }