Java:线程顺序

下面的代码发现输出结果不是顺序,不是从小到大,如何保证它是从小到大的顺序?

java代码

public class TestSync { /** * @param args */ public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread(new Thread1()).start(); } } public int getNum(int i) { synchronized (this) { i++; } return i; } static class Thread1 implements Runnable { static Integer value = 0; @Override public void run() { TestSync ts = new TestSync(); value = ts.getNum(value); System.out.println("thread1:" + value); } } } 

你想达到什么目的? 您的代码仅同步对特定TestSync实例的调用。 由于每个线程都创建自己的实例,所以就像你根本没有同步任何东西。 您的代码没有做任何事情来同步或协调跨不同线程的访问。

我建议以下代码可能更符合您要完成的任务:

 public static void main (String[] args) throws java.lang.Exception { for (int i = 0; i < 10; i++) { new Thread1().start(); } } //no need for this to be an instance method, or internally synchronized public static int getNum(int i) { return i + 1; } static class Thread1 extends Thread { static Integer value = 0; @Override public void run() { while (value < 100) { synchronized(Thread1.class) { //this ensures that all the threads use the same lock value = getNum(value); System.out.println("Thread-" + this.getId() + ": " + value); } //for the sake of illustration, we sleep to ensure some other thread goes next try {Thread.sleep(100);} catch (Exception ignored) {} } } } 

这里的实例: http : //ideone.com/BGUYY

请注意, getNum()基本上是多余的。 如果你替换value = getNum(value);上面的例子将会起作用value = getNum(value); 用简单的value++;

虽然有人想知道为什么这是必要的,但这是一种方法。 它不优雅,但代表了原始程序的最小变化:

 import java.util.concurrent.*; public class TestSync { public static void main(String[] args) { ExecutorService service = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { service.submit(new Thread1()); } } public int getNum(int i) { synchronized (this) { i++; } return i; } static class Thread1 implements Runnable { static Integer value = 0; @Override public void run() { TestSync ts = new TestSync(); value = ts.getNum(value); System.out.println("thread1:" + value); } } 

}

这是一个更好的版本。 它使用AtomicInteger作为计数器(在这种情况下可能是过度杀伤)来删除令人不快的getNum()方法:

 import java.util.concurrent.*; import java.util.concurrent.atomic.*; public class TestSync { static private AtomicInteger i = new AtomicInteger(0); public static void main(String[] args) { ExecutorService service = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { service.submit(new MyThread(i)); } try { Thread.sleep(2*1000); } catch(Exception ex) {} service.shutdown(); } static class MyThread implements Runnable { private int num = 0; public MyThread(int num) { this.num = num; } @Override public void run() { int value = i.incrementAndGet(); System.out.println("thread # " + num + " value = " + value); } } } 

更不用说,无法保证在线程中运行时执行哪些订单代码。 这是由所谓的时间延迟引起的。 CPU将为特定线程分配“切片”时间。 切片启动时,它会有效地暂停线程,并允许其他线程获得切片。 最终,它会回到暂停的线程并给它们额外的时间片,但这真的取决于CPU。

具有多个核和/或超线程允许CPU同时给予更multithreading时间片。

但是,正如我所说的那样,无法确保哪个顺序线程是时间序列的,以及每个单独线程将在何时何地暂停和恢复。

这意味着“i ++”操作(以及相关打印)的完成顺序不一定是您启动线程的顺序。 此外,线程之间的任何共享变量都应该使用“volatile”修饰符声明,以防止该值的线程级缓存。

如果你想强制顺序排序,你应该首先考虑为什么你在使用线程而不是顺序循环。

我不是Java程序员,但同步锁不会阻止无序调用getNum()。 并且因为Thread1在不同的线程上运行,所以调度程序可以按任何顺序自由运行10个线程。

同步保证的是,一次只有一个线程可以在同步部分内执行代码。

如果要进行顺序执行,请在一个线程中调用所有getNums()。 或者像ExecutorService一样使用线程队列。

实际上有两个问题。

1)。 Synchronization块特定于Thread1实例

你应该使用其中之一

  synchronized(TestSync.class) { // // } 

要么

 synchronized(Thread1.class) { // // } 

2)。 核心问题是。 Setting the static variableSystem.out.println()也应该同步,以便按顺序generationprinting值。

重写你的main()方法,如:

 public static void main(String[] args) { for (int i = 0; i < 10; i++) { Thread th = new Thread(new Thread1()); th.start(); try { th.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }