Java线程,错误的计数器

时间:2014-08-11 09:29:38

标签: java multithreading

我在片段下面运行,我得到了意想不到的行为。可能它正在以正确的方式工作,但我需要让它以其他方式工作。详情如下。

import java.util.ArrayList;
import java.util.List;

public class TaskExample {

public static void main(String[] args) throws InterruptedException {
    final PositionHolder holder = new PositionHolder();
    final List<Integer> data = new ArrayList<Integer>();
    List<Thread> threads = new ArrayList<Thread>();
    for (int i = 0; i < 20; i++) {
        holder.setPosition(i);
        Thread t = new Thread() {

            @Override
            public void run() {
                data.add(holder.getPosition());
            }
        };

        t.start();
        threads.add(t);
    }

    for (Thread thread : threads) {            
            thread.join();
        }

    for(int i : data){
        System.out.println(i);
    }
}
}

class PositionHolder {

    int position = 0;

    public void setPosition(int position) {
        this.position = position;
    }

    public int getPosition() {
        return this.position;
    }
}

我得到了结果:

  

10 12 9 8 6 6 5 4 2 1 16 16 18 19 19 19 19 19 19 19

为什么呢?我想得到:

  

1 2 3 4 ...... 20

是否有任何选项可以改进此代码段?

4 个答案:

答案 0 :(得分:1)

试试这段代码;)

import java.util.ArrayList;
import java.util.List;

public class ogr
{

    public static void main(String[] args) throws InterruptedException {
        final PositionHolder holder = new PositionHolder();
        final List<Integer> data = new ArrayList<Integer>();
        for (int i = 0; i < 20; i++) {
            holder.setPosition(i);
            Thread t = new Thread() {

                @Override
                public void run() {
                    data.add(holder.getPosition());
                }
            };

            t.start();
            t.join();
        }

        for (int i : data) {
            System.out.println(i);
        }
    }
}

class PositionHolder
{

    int position = 0;

    public void setPosition(int position) {
        this.position = position;
    }

    public int getPosition() {
        return this.position;
    }
}

答案 1 :(得分:0)

您不能保证holder.getPosition()将获得您使用holder.setPosition(i)设置的相同位置值,因为getHolder调用是不同线程的一部分并由多个线程调用。这是因为您在所有线程中共享相同的PlaceHolder。如果你想获得你想要的输出,我会建议为每个线程使用不同的PlaceHolder实例。

import java.util.ArrayList;
import java.util.List;

public class TaskExample {

public static void main(String[] args) throws InterruptedException {
     final List<Integer> data = new ArrayList<Integer>();
     List<Thread> threads = new ArrayList<Thread>();
     for (int i = 0; i < 20; i++) {
         // Create new instance
         final PositionHolder holder = new PositionHolder(i);
         Thread t = new Thread() {
             @Override
             public void run() {
                 data.add(holder.getPosition());
             }
         };
     t.start();
     threads.add(t);

     for (Thread thread : threads) {            
         thread.join();
     }

     for(int i : data){
         System.out.println(i);
     }
}

class PositionHolder {
    private int position = 0;

    public PositionHolder(int position) {
        this.position = position;
    }

    public int getPosition() {
        return this.position;
    }
}`

答案 2 :(得分:0)

如果没有像join()这样的同步机制,就无法保证线程的执行顺序(参见Fincio提出的代码)。

您正在多次获得相同的数字,因为您对所有线程使用相同的PositionHolder对象,因此,变量position会被您启动的每个线程修改。试图用Object而不是int来做同样的事情可能会让你ConcurrentAccessException。为了避免这种情况,每个线程都应该有自己的PositionHolder实例(就像Saket提供的代码一样)。但即便如此,也无法保证线程的执行顺序。

答案 3 :(得分:0)

使用线程编程有时需要一些技巧来使线程有效。显然它不会那么自然。例如,检查以下内容。

import java.util.ArrayList;
import java.util.List;

public class ogr{
public static void main(String[] args) throws InterruptedException {
    ArrayList<PositionHolder> holders=new ArrayList<PositionHolder>();
    final PositionHolder holder = new PositionHolder();
    final List<Integer> data = new ArrayList<Integer>();
    for (int i = 0; i < 20; i++) {
        Thread t = new Thread() {

            @Override
            public void run() {
                data.add(getSetPosition());
            }
        };
        holders.add(holder)
        t.start();

    }
    for (Thread thread : threads) {            
        thread.join();
    }

    SortByPosition(holders); //you can implement this easy by sorting arraylist by their positions

    for (int i : data) {
        System.out.println(i);
    }
}
}

class PositionHolder{

static int staticPosition=0;
int position = 0;

public int synchronized getSetPosition() {
       this.position = staticPosition++;
       return position;
}

 //  public void setPosition(int position) {
 //      this.position = position;
 //  }

public int getPosition() {
    return this.position;
}
}