下面的代码发现输出结果不是顺序,不是从小到大,如何保证它是从小到大的顺序?
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);
}
}
}
答案 0 :(得分:2)
虽然有人想知道为什么这是必要的,但这是一种方法。它并不优雅,但代表了对原始程序的微小改动:
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);
}
}
}
答案 1 :(得分:2)
你想要完成什么?您的代码仅同步对特定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++;
,则上述示例的工作方式相同。
答案 2 :(得分:1)
更不用说,无法保证在线程中运行时执行的订单代码是什么。这是由所谓的时间延迟引起的。 CPU将为特定线程分配“切片”时间。当切片启动时,它会有效地暂停线程,并允许其他线程获得切片。最终,它会回到暂停的线程并给它们额外的时间片,但这真的取决于CPU。
拥有多个内核和/或超线程允许CPU同时为更多线程提供时间片。
但是,正如我所说的那样,无法保证哪个顺序线程是时间点的,以及每个线程将在何时何地暂停和恢复。
这意味着“i ++”操作(以及相关打印)的完成顺序不一定是您启动线程的顺序。此外,线程之间的任何共享变量都应该使用“volatile”修饰符声明,以防止线程级别缓存该值。
如果你想强制进行顺序排序,你应该首先考虑为什么你首先使用线程而不是顺序循环。
答案 3 :(得分:0)
我不是Java程序员,但同步锁不会阻止无序调用getNum()。并且因为Thread1在不同的线程上运行,所以调度程序可以按任何顺序自由运行10个线程。
同步保证的是,一次只有一个线程可以在同步部分内执行代码。
如果您想要顺序执行,请在一个线程中调用所有getNums()。或者像ExecutorService一样使用线程队列。
答案 4 :(得分:0)
实际上有两个问题。
1)。 Synchronization
块特定于Thread1
实例
你应该使用
synchronized(TestSync.class) {
//
//
}
或
synchronized(Thread1.class) {
//
//
}
2)。核心问题是。
Setting the static variable
和System.out.println()
也应同步,以便generation
和printing
值依次排列。
答案 5 :(得分:0)
重写您的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();
}
}
}