迭代一个线程

时间:2015-08-06 16:29:24

标签: java multithreading

我需要通过List迭代,将List中的每个元素添加到一个新List中,并从原始列表中删除该元素。我有三个线程在同一个原始列表上运行相同的进程。 每个帖子都需要添加3本书,并删除每个通过循环的3本书。

这是我的代码:

    public class BookBoxer {  
  static List<Book> library = new ArrayList<>();

  static Librarian librarian1 = new Librarian();
  static Thread thread1 = new Thread(librarian1, "librarian1");

  static Librarian librarian2 = new Librarian();
  static Thread thread2 = new Thread(librarian2, "librarian2");

  static Librarian librarian3 = new Librarian();
  static Thread thread3 = new Thread(librarian3, "librarian3");


  public static void main(String[] args) {
    buldLibrary();

    thread1.start();
    thread2.start();
    thread3.start();

    System.out.println("Librarian 1: total books: "+ librarian1.getTotalBooks()+ 
        " || total value: $" + librarian1.getTotalValue());
    System.out.println("librarian 1 book: " + librarian1.box.toString());
    System.out.println();

    System.out.println("Librarian 2: total books: "+ librarian2.getTotalBooks()+ 
        " || total value: $" + librarian2.getTotalValue());
    System.out.println("librarian 2 book: " + librarian2.box.toString());
    System.out.println();

    System.out.println("Librarian 3: total books: "+ librarian3.getTotalBooks()+ 
        " || total value: $" + librarian3.getTotalValue());
    System.out.println("librarian 3 book: " + librarian3.box.toString());
    System.out.println();

    System.out.println("This is the new library " + library);

    System.out.println("The library has books: " + libraryHasBooks());
  }

  public static void buldLibrary() {
    int i = 1;
    while(i < 101) {
      Book book = new Book("Book #");
      library.add(book);
      book.incrementPrice();
      System.out.println(book.toString());
      i++;
    }
  }

  public static boolean libraryHasBooks() {
    if(library.isEmpty()) {
      return false;
    }
    return true;
  }

static class Librarian implements Runnable {
     private static long sleepTime = ((long)(Math.random() * 1000));
     private double totalValue;
     private int totalBooks = 0;
     List<Book> box = new ArrayList<>();

    private void getBook(List<Book> aLibrary) { 
      Iterator<Book> libraryIterator = aLibrary.iterator();
        if(libraryIterator.hasNext()) {
        box.add(libraryIterator.next());
        }
    }  

    private void removeBook(List<Book> aLibrary) { 
      Iterator<Book> libraryIterator = aLibrary.iterator();
      if(libraryIterator.hasNext()) {
      libraryIterator.next();
      libraryIterator.remove();
      }
    }

    private double getTotalValue() {
      Iterator<Book> boxIterator = box.iterator();
        while(boxIterator.hasNext()) {
        totalValue += boxIterator.next().getPrice();
        }
        return totalValue;
      }

    private int getTotalBooks() {
      for(Book i : box) {
        totalBooks++;
      } 
      return totalBooks;
    }

    public void performAction() { 
     for(int x = 1; x <= 3; x++) {
       this.getBook(library);
       this.removeBook(library);
     }
   }

    @Override
    public void run() { 
      while(libraryHasBooks())
        {
          this.performAction();
          try 
          {
            Thread.sleep(sleepTime);
          } catch (InterruptedException e) { e.printStackTrace(); }
        }
      }

  }
}

这是我的输出:

    Librarian 1: total books: 3 || total value: $3.75
librarian 1 book: [Name: Book #1 Price: $1.0, Name: Book #2 Price: $1.25, Name: Book #3 Price: $1.5]

Librarian 2: total books: 3 || total value: $6.0
librarian 2 book: [Name: Book #4 Price: $1.75, Name: Book #5 Price: $2.0, Name: Book #6 Price: $2.25]

Librarian 3: total books: 3 || total value: $8.25
librarian 3 book: [Name: Book #7 Price: $2.5, Name: Book #8 Price: $2.75, Name: Book #9 Price: $3.0]

This is the new library [Name: Book #10 Price: $3.25, Name: Book #11 Price: $3.5, Name: Book #12 Price: $3.75, Name: Book #13 Price: $4.0, Name: Book #14 Price: $4.25, Name: Book #15 Price: $4.5, Name: Book #16 Price: $4.75, Name: Book #17 Price: $5.0, Name: Book #18 Price: $5.25, Name: Book #19 Price: $5.5,....................

The library has books: true

Exception in thread "librarian3" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
    at java.util.ArrayList$Itr.next(ArrayList.java:791)
    at com.github.salvadore_jefferson.libraryapp.BookBoxer$Librarian.getBook(BookBoxer.java:80)
    at com.github.salvadore_jefferson.libraryapp.BookBoxer$Librarian.performAction(BookBoxer.java:109)
    at com.github.salvadore_jefferson.libraryapp.BookBoxer$Librarian.run(BookBoxer.java:118)
    at java.lang.Thread.run(Thread.java:722)

谢谢大家!!

4 个答案:

答案 0 :(得分:0)

一个线程通常不允许修改Collection,而另一个线程正在迭代它。见ConcurrentModificationException

答案 1 :(得分:0)

有一个Concurrent Queue实现应该做你想要的(你所描述的代码似乎更像是一个队列而不是列表)。

如果你必须使用一个列表(好吧,队列是一个列表,但也许你有特殊要求),你将不得不同步你的方法,这将使整个线程没有意义 - 但如果它&#39;那么这可能是他们想要教给你的东西......如果是这样的话,不要在列表上循环(迭代器将破灭)并将同步(列表)放在一起与列表交互的代码的每个部分。

另外一定要把你的阅读和删除内容放在同一个同步语句中 - 因为你编写的是防御性思考。任何另一个线程可以滑入的洞和“攻击”#34;你应该考虑一下!即使是像x ++这样的东西,如果它在2个线程中并且没有得到适当保护,也会搞砸。

答案 2 :(得分:0)

  1. 你可以通过同步列表来实现。
  2. 您可以等待一个共同的共享对象。

答案 3 :(得分:0)

我以为我会用我为改变这个问题所做的更改来更新这个问题。以下是更重要的代码更改:

static Queue<Book> library = new ConcurrentLinkedQueue<>();

public static boolean libraryHasBooks() {
    if (library.isEmpty()) {
      System.out.println("Closing Application");
      System.out.println("The Library has : " + library);
      librarian1.getResults();
      librarian2.getResults();
      librarian3.getResults();
      System.exit(0);
    }
    return true;
  }

private synchronized void removeBook() {
      Iterator<Book> libraryIterator = library.iterator();
      if (libraryIterator.hasNext()) {
        libraryIterator.next();
        library.poll();
      }
    }
public synchronized void performAction() {
      for (int x = 1; x <= 3; x++) {
        this.getBook();
        this.removeBook();
        this.getTotalValue();
        this.getTotalBooks();
      }
    }

public void getResults() {
     System.out.println();
     System.out.println(this.getName() + ": Has " + this.getTotalBooks() +" books. "  
     + " With a total value of $" + this.getTotalValue());
     System.out.println(this.getName() + ": Has " + this.box.toString());
    }

@Override
    public void run() {
      while(libraryHasBooks()) {
        this.performAction();
        try
        {
          Thread.sleep(sleepTime);
        }
        catch(InterruptedException e) { e.printStackTrace(); }
      }      
    }