Java [threads] - 总结具有多个线程的表似乎不起作用

时间:2015-05-10 14:20:02

标签: java multithreading synchronization

我正在学习java,并试图用多个线程来总结表中的元素,但我总是得到错误的结果。

我尝试了4种不同的线程同步方法,但都失败了。一切都在评论中解释。

我的结果(不好):

  

没有线程:4949937,15ms   线程:4944805,78ms

也许我过早地在summarizeT()上执行System.out.println?我的意思是在所有线程完成工作之前。使用.join(),summarizeT()方法效果很好但是。 .join()阻塞“主”线程,直到所有其他线程完成?

主要课程:

public class Main 
{
static int size = 100000; //size of tab
static int length = 100; //each thread gets 100 elements of tab, thread 1 calculates sum from 0 to 99, thread 2 from 100 to 199 etc.
static int[] tab = new int[size];

static Random generator = new Random();

static void initialize()
{
    for (int i = 0; i < size; i++)
        tab[i] = generator.nextInt(100);
}

static int summarize() //summarize with only one thread
{
    int sum = 0;
    for (int i = 0; i < size; i++)
        sum += tab[i];
    return sum;
}

static int summarizeT() //summarize with more threads (size / length)
{
    int threadsCounter = size/length;
    int start = 0; //pointer to table from where each thread should start counting
    int[] sum = new int[1]; //I am sharing the sum value between threads with table, not sure if it is best method to pass the value between them
    sum[0] = 0;
    Thread[] threads = new Thread[threadsCounter]; //nedeed for .join() test
    for (int i = 0; i < threadsCounter; i++)
    {
        threads[i] = new Thread(new MyThread(tab, start, sum));
        threads[i].start();
        start += length; //moving the start pointer, next thread should start counting from next 100 indexes 
    }
    /*for (int i = 0; i < threadsCounter; i++) // adding .join() solves the problem, but is it a good solution?
    {
        try {
            threads[i].join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }*/
    return sum[0];
}


public static void main(String[] args) 
{
    initialize();
    long start = Calendar.getInstance().getTimeInMillis();
    System.out.println("Without threads: " + summarize() + ", " + (Calendar.getInstance().getTimeInMillis() - start) + "ms");
    start = Calendar.getInstance().getTimeInMillis();
    System.out.println("With threads: " + summarizeT() + ", " + (Calendar.getInstance().getTimeInMillis() - start) + "ms"); //giving wrong answer
}
}

MyThread课程:

  import java.util.concurrent.Semaphore;

  public class MyThread extends Thread
  {
int[] tab;
int[] sum;
int start;

         MyThread(int tab[], int start, int sum[]) //in args: main table, starting index, value that is being shared between threads
{
    this.tab = tab;
    this.start = start;
    this.sum = sum;
}

@Override
public void run() 
{
    int end = start + Main.length; //place where thread should stop counting
    int temp = 0; //nedeed to sumarize the "subtable"
    while (start < end)
    {
        temp += tab[start];
        start++;
    }

    // Method 1
    Semaphore semaphore = new Semaphore(1);
    try {
        semaphore.acquire();
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }
    try 
    {
        sum[0] += temp;
    } catch (Exception e) {
    } finally {
       semaphore.release();
    }

    // Method 2
    /*Object lock = new Object();
    synchronized(lock)
    {
        sum[0] += temp;
    }*/

    // Method 3
    /*synchronized(this)
    {
        sum[0] += temp;
    }*/

    // Method 4
    //summarize(temp);

    // Method 5 - no threads synchronization, works only when .join() is used, the same as other methods
    //sum[0] += temp;
}

private synchronized void summarize(int value)
{
    sum[0] += value;
}
}

1 个答案:

答案 0 :(得分:0)

您的解决方案存在一些问题。

您应该使用AtomicInteger来保存结果。这样你就不需要同步和更新了。

BTW您同步的方式无效。要使信号量工作,您需要在所有线程之间共享相同的实例。而你的try / catch / finally块无效。您应该acquire()并在一个try块中汇总更新,最后在其中release()。那样你就做到了。即使acquire()失败,您也可以进行总结更新。

您也可以从summarizeT()返回,而无需等待线程完成。您必须实现thread.join()逻辑或其他等待方式。