2017-01-14 19 views
0

は私の擬似コードです:Java-eeで再帰ツリーを構築するには?ここ

class Builder implements Callable<T> { 
    T obj; 
    ManagedExecutorService pool; 

    Builder (T obj, ManagedExecutorService pool){ 
    this.obj = obj; 
    this.pool = pool; 
    } 

    T call(){ 
    build(); 
    } 

    private void build(){ 
     // skip if already traversed 
     return isTraversed(obj); 

     // call db and get obj's one-to-many relationships 
     Collection<T> colOfChildObj = DbUtil.getChildrenPOJO(obj); 
     for (<Collection>T childObj : colOfChildObj){ 
      this.pool.submit(new Builder(childObj, this.pool)); 
     } 
     // set children as-is, when the submit above completes, 
     // it will update childObj and thus will reflect 
     // obj.childObj.itsChidren etc. For this though the caller 
     // has to wait until all submits are processed 
     obj.setChildren(colOfChildObj); 
    } 
} 

のJava-EEはForkJoinPoolサポートしていないので - 問題外です。それでは、ManagedThreadFactoryとManagedExecutorServiceのどちらを使ってそれをやりますか?私の本当の挑戦は、Java-eeでpool.shutdown()またはpool.awaitTerminationを呼び出せないことが原因です。私がやるのであれば、発信者からの、:

class Caller() { 
    T getObjGraph(T rootObj){ 
    pool.submit(new Builder(rootObj)); 
    T objGraph = pool.get(); 
    return objGraph; 
    } 
} 

その後、私の方法は、すべてのpool.submit(新しいビルダー(childObj、プール))を待たないので、私のオブジェクトは、すべてが設定され、不完全である持っていません。 pool.submitによって返されたすべてのFuturesをブロッキングキューに入れることを考えましたが、私はツリートラバーサルが完了したことを呼び出し元に通知する方法がわかりません。私は、ツリートラバーサルが完了したときに0に達するカウンタを持っていますが、クライアントがトップレベルのノードを送信しているので、while(isCounter = 0)なしでJava-eeで待機する方法がわかりません。 CPUの豚。

任意のポインタ?

+0

達成しようとしていることを説明してください。タイトルは、あなたがツリーを構築しようとしていることを示唆しています。しかし、問題はあなたが何かをしようとしていることを示唆しています(しかし何ですか?)同時に。あなたは何を達成しようとしていますか?複数のスレッドから管理されたJPAエンティティを処理しようとしているようです。これはすでに間違っています。マネージエンティティはスレッドセーフではありません。スレッドセーフではない永続コンテキストにリンクされています。 –

+0

追加情報を参照してください。これらはManagedオブジェクトではなく、単にPOJOです。 – donlys

答えて

1

私はあなたがしようとしていることを理解していると思います。スレッドセーフカウンタを使用するだけで、指定したノードの新しいタスクを作成してサブミットするたびにそのカウンタを増やし、このノードのタスクが終了するとそのカウンタを減分することができます。

メインスレッドでは、処理するノードの残りの数は0です。そして各タスクでは、ロックに通知してタックが終了したことを知らせます。

これは完全な例です。各ノードが名前を持つツリーから開始し、このツリーを別のツリーに変換します。ここで、各ノードは元の名前と連結された「Hello」です。

public class Tree { 

    public static void main(String[] args) throws ExecutionException, InterruptedException { 
     Node root = new Node("R"); 

     Node c1 = new Node("C1"); 
     Node c2 = new Node("C2"); 

     root.addChild(c1); 
     root.addChild(c2); 

     Node gc11 = new Node("GC11"); 
     Node gc12 = new Node("GC12"); 
     c1.addChild(gc11); 
     c1.addChild(gc12); 

     Node gc21 = new Node("GC11"); 
     Node gc22 = new Node("GC12"); 
     c2.addChild(gc21); 
     c2.addChild(gc22); 

     System.out.println("root = " + root); 

     ExecutorService executor = Executors.newFixedThreadPool(4); 
     final Object lock = new Object(); 
     final AtomicInteger remaining = new AtomicInteger(0); 
     Future<Node> result = executor.submit(new HelloTask(root, null, executor, remaining, lock)); 

     synchronized (lock) { 
      while (remaining.get() != 0) { 
       lock.wait(); 
      } 
     } 

     Node helloRoot = result.get(); 

     System.out.println("helloRoot = " + helloRoot); 

     executor.shutdown(); 
    } 

    private static class HelloTask implements Callable<Node> { 
     private final Node source; 
     private final Node parent; 
     private final ExecutorService executorService; 
     private final Object lock; 
     private final AtomicInteger remaining; 

     public HelloTask(Node source, Node parent, ExecutorService executorService, AtomicInteger remaining, Object lock) { 
      this.source = source; 
      this.parent = parent; 
      this.executorService = executorService; 
      this.lock = lock; 
      this.remaining = remaining; 
      remaining.incrementAndGet(); 
     } 

     @Override 
     public Node call() throws Exception { 
      // simulate some time 
      Thread.sleep(1000L); 
      Node result = new Node("Hello " + source.getName()); 
      if (parent != null) { 
       parent.addChild(result); 
      } 
      for (Node child : source.getChildren()) { 
       executorService.submit(new HelloTask(child, result, executorService, remaining, lock)); 
      } 

      remaining.decrementAndGet(); 
      synchronized (lock) { 
       lock.notifyAll(); 
      } 
      return result; 
     } 
    } 

    private static class Node { 
     private final String name; 
     private final List<Node> children = new CopyOnWriteArrayList<>(); 

     public Node(String name) { 
      this.name = name; 
     } 

     public String getName() { 
      return name; 
     } 

     public List<Node> getChildren() { 
      return children; 
     } 

     public void addChild(Node child) { 
      this.children.add(child); 
     } 

     @Override 
     public String toString() { 
      StringBuilder sb = new StringBuilder(); 
      sb.append(name); 
      sb.append('\n'); 
      children.forEach(sb::append); 
      return sb.toString(); 
     } 
    } 
} 
+0

はい - 正しく理解しています。唯一のことは、java-eeコンテナで実行するには、lock.wait()またはlock.notifyAll()オペレーションを呼び出すことができない仕様だからです。また、私はexecutor.shutdown()を実行できません。 - 私は同期(ロック)ループとは無関係だと思います。これが何とか未来に包まれる方法はありますか?したがって、synchronized(ロック)の代わりにresult.get()を実行します。これはツリートラバースの完了を解決しますか? – donlys

+0

ここでのシャットダウンは、コマンドラインデモが無限に実行されるのを避けるためのものです。あなたはあなたのサーバーでそれを使用しません。あまりにも慎重に仕様を読んでいると思います。このようにwait()とnotify()を呼び出すことは問題ではありません。たとえば、HTTPリクエストを同期的に送信するだけでなく、応答が返るまでブロッキングするだけではありません。 –

+0

result.get()は、ルートノードが処理されるとすぐに、子ノードがまだ処理されている間に返されるため、行うことはできません。 –

関連する問題