线程需要等待列表更新

时间:2017-04-04 14:27:26

标签: java multithreading synchronization

下面的课程会在特定的时间间隔内更新地图。

public class CheckerThread extends Thread {

   private volatile HashMap<String, Integer> map = new HashMap<>();

   @Override
   public void run() {
           while (true) {
                updateMap();
           try {
             Thread.sleep(1000);
            }
           catch (InterruptedException e) {
             // Do something
            }
          }
    }

  private void updateMap() {
   HashMap<String, Integer> localMap = new HashMap<>();
   int count = 0;
     while (count < 10) {
        localMap.put(count + "a", count);
      count++;
     }
        this.map = localMap;
   }


   public Map<String, Integer> getMap() {
    return this.map;
   }
}

下面的类调用方法getMap()来获取Map。我需要确保列表完全更新,然后才能在类#34; CheckerThread&#34;中返回地图。该方法应该等到地图更新。

public class GetterThread extends Thread {

 private final CheckerThread checkerThread;

 public GetterThread(final CheckerThread checkerThread) {
    this.checkerThread = checkerThread;
  }

  @Override
  public void run() {
       System.err.println(this.checkerThread.getMap());
    }
  }

另一个Main创建线程。

public class MainThread extends Thread {
 public static void main(final String[] args) throws   InterruptedException {
  int i = 0;
  GetterThread[] getterThreads = new GetterThread[5];
  CheckerThread checkerThread = new CheckerThread();
  checkerThread.start();
   while (i < 5) {
      getterThreads[i] = new GetterThread(checkerThread);
      getterThreads[i].start();
      Thread.sleep(1000);
       i++;
    }
  }
 }
}

3 个答案:

答案 0 :(得分:1)

线程的想法是可以的,但还不够(大多数是因为线程在完成工作后不会返回任何内容......)如果你仍想使用线程,那么你将以等待/加入/通知方法......

您可以代替thread --> runnable使用task --> callable

Callables 是类固醇上的线程,你可以在 ExecutorService 中执行它们并等到作业完成后得到一个结果,让你知道一切是否正常或不!!

以此为例,查阅文档以获取更多信息:

public class _Foo {

    public static void main(String... args) throws InterruptedException, ExecutionException {
        ExecutorService exService = Executors.newSingleThreadExecutor();
        FutureTask<Boolean> futureTask = new FutureTask<>(new MapCleaner());
        exService.execute(futureTask);
        System.out.println("Was everything ok??: " + futureTask.get());
    }
}

class MapCleaner implements Callable<Boolean> {
    @Override
    public Boolean call() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException ex) {
            System.out.println(ex);
        }
        return System.currentTimeMillis() % 2 == 0;
    }
}

答案 1 :(得分:0)

你看过期货了吗? Future.get()等待任务完成。这可能是你需要的吗?

public class MyCallable implements Callable<Map<String, Integer>> {

    private volatile HashMap<String, Integer> map = new HashMap<>();
    private boolean wait = true;

    public void call() {
        while (wait) {
            updateMap();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {

            }
        }
        return map;
    }

    private void updateMap() {
        HashMap<String, Integer> localMap = new HashMap<>();
        int count = 0;
        while (count < 10) {
            localMap.put(count + "a", count);
        }
        this.map = localMap;
        wait = false;
    }

}

然后打电话给未来

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Map<String, Integer>> future = executor.submit(new MyCallable());
// Future.get() waits for task to get completed
Map<String, Integer> myMap = fut.get();

答案 2 :(得分:0)

根据您的示例,我认为您应该使用BlockingQueue。将元素放入“checker”线程的队列中,并在“getter”线程中使用阻塞等待读取它们。这很简单,非常干净,不需要太多更改。

队列不仅可以解决您的同步问题,还可以解决计时问题。无论你的线程运行在哪个顺序,你的getter线程总是等待数据可用,然后返回。它几乎是防弹的。

顺便说一句,你的检查线程中有一个错误。你把10个元素放到了地图中,但是你永远不会增加count,所以循环永远不会退出(它会将无数个元素放入地图中,最终会出现内存不足的错误)。

此外,永远不要抓住并忽略InterruptedException。如果你被打断,你几乎总想退出你的线程。 C.F. Brian Goetz的书 Java Concurrency in Practice 了解更多。

public class SimpleThreading
{
   public static void main(String[] args) throws InterruptedException {
      MainThread.main(args);
   }
}

class MainThread extends Thread
{

   public static void main( final String[] args )
           throws InterruptedException
   {
      int i = 0;
      GetterThread[] getterThreads = new GetterThread[ 5 ];
      CheckerThread checkerThread = new CheckerThread();
      checkerThread.start();
      while( i < 5 ) {
         getterThreads[i] = new GetterThread( checkerThread );
         getterThreads[i].start();
         Thread.sleep( 1000 );
         i++;
      }
   }
}

class GetterThread extends Thread
{

   private final CheckerThread checkerThread;

   public GetterThread( final CheckerThread checkerThread )
   {
      this.checkerThread = checkerThread;
   }

   @Override
   public void run()
   {
      try {
         System.out.println("waiting..." + checkerThread.getQueue() );
         System.err.println( this.checkerThread.getQueue().take() );
      } catch( InterruptedException ex ) {
         // exit on interrupt
      }
   }
}

class CheckerThread extends Thread
{

   private HashMap<String, Integer> map;
   private final BlockingQueue<Map<String,Integer>> queue =
           new LinkedBlockingQueue<>();

   @Override
   public void run()
   {
      while( true )
         try {
            updateMap();
            queue.put( map );
            System.out.println( "Added " + map );
            Thread.sleep( 1000 );
         } catch( InterruptedException e ) {
            return; // exit on interrupt
         }
   }

   private void updateMap()
   {
      HashMap<String, Integer> localMap = new HashMap<>();
      int count = 0;
      while( count < 10 )
         localMap.put( count + "a", count++ );
      this.map = localMap;
   }

   public BlockingQueue<Map<String, Integer>> getQueue()
   {
      return queue;
   }
}