在多个线程java之间共享一个对象

时间:2014-06-17 19:36:59

标签: java multithreading

我希望能够在依赖同一个全局变量的同时运行两个方法。第一种方法定期更新共享变量,但永远不会完成运行。第二种方法记录时间。当时间用完时,第二个方法从第一个方法返回共享变量的最后一个结果。下面是我到目前为止,在我需要帮助的地方注释了pseduocode。

package learning;

public class testmath{
    public static void main(String[] args){

        long finishBy = 10000;
        int currentresult = 0;

        /*
         * run eversquare(0) in  a seperate thread /in parallel
         */


        int finalresult = manager(finishBy);
        System.out.println(finalresult);
    }


    public static int square(int x){
        return x * x;
    }

    public static void eversquare(int x){
        int newresult;
        while(2 == 2){
            x += 1;
            newresult = square(x);
            /*
             * Store newresult as a global called currentresult
             */

        }
    }



    public static int manager(long finishBy){


        while(System.currentTimeMillis() + 1000 < finishBy){
            Thread.sleep(100);
        }

        /*
         * Access global called currentresult and create a local called currentresult
         */     
        return currentresult;

    }

}

1 个答案:

答案 0 :(得分:2)

您只需要运行一个额外的线程:

public class Main {
  /**
   * Delay in milliseconds until finished.
   */
  private static final long FINISH_BY = 10000;
  /**
   * Start with this number.
   */
  private static final int START_WITH = 1;
  /**
   * Delay between eversquare passes in milliseconds.
   */
  private static final long DELAY_BETWEEN_PASSES = 50;
  /**
   * Holds the current result. The "volatile" keyword tells the JVM that the
   * value could be changed by another thread, so don't cache it. Marking a
   * variable as volatile incurs a *serious* performance hit so don't use it
   * unless really necessary.
   */
  private static volatile int currentResult = 0;

  public static void main(String[] args) {
    // create a Thread to run "eversquare" in parallel
    Thread eversquareThread = new Thread(new Runnable() {
      @Override public void run() {
        eversquare(START_WITH, DELAY_BETWEEN_PASSES);
      }
    });

    // make the eversquare thread shut down when the "main" method exits
    // (otherwise the program would never finish, since the "eversquare" thread
    // would run forever due to its "while" loop)
    eversquareThread.setDaemon(true);

    // start the eversquare thread
    eversquareThread.start();

    // wait until the specified delay is up
    long currentTime = System.currentTimeMillis();
    final long stopTime = currentTime + FINISH_BY;
    while (currentTime < stopTime) {
      final long sleepTime = stopTime - currentTime;
      try {
        Thread.sleep(sleepTime);
      } catch (InterruptedException ex) {
        // in the unlikely event of an InterruptedException, do nothing since
        // the "while" loop will continue until done anyway
      }
      currentTime = System.currentTimeMillis();
    }
    System.out.println(currentResult);
  }

  /**
   * Increment the value and compute its square. Runs forever if left to its own
   * devices.
   *
   * @param startValue
   * The value to start with.
   *
   * @param delay
   * If you were to try to run this without any delay between passes, it would
   * max out the CPU and starve any other threads. This value is the wait time
   * between passes.
   */
  private static void eversquare(final int startValue, final long delay) {
    int currentValue = startValue;
    while (true) { // run forever (just use "true"; "2==2" looks silly)
      currentResult = square(currentValue); // store in the global "currentResult"
      currentValue++; // even shorter than "x += 1"
      if (delay > 0) {
        try { // need to handle the exception that "Thread.sleep()" can throw
          Thread.sleep(delay);
        } catch (InterruptedException ex) { // "Thread.sleep()" can throw this
          // just print to the console in the unlikely event of an
          // InterruptedException--things will continue fine
          ex.printStackTrace();
        }
      }
    }
  }

  private static int square(int x) {
    return x * x;
  }
}

我还应该提到&#34; volatile&#34;关键字适用于(大多数)基元,因为您现在看到的任何JVM都可以保证它们会以原子方式进行修改。对象不是这种情况,您需要使用同步块和锁来确保它们始终被&#34;看到&#34;处于一致的状态。

大多数人还会提到你应该在方法本身上使用synchronized关键字,而是在特定的&#34;锁定&#34;宾语。通常,此锁定对象不应在代码外部可见。这有助于防止人们错误地使用您的代码,让自己陷入麻烦,然后试图责怪您。 :)