【问题标题】:Where do i have to use synchronized?我必须在哪里使用同步?
【发布时间】:2015-03-27 01:19:35
【问题描述】:

我做了一些研究,但找不到解决这个问题的方法。

从这个主题Synchronization, When to or not to use? 我知道我可以使用synchronized,但这样做并不能解决问题。

情况是我有一个方法,其中Thread 用于创建ArrayList。在同一个Thread 中,另一个methodBufferedReader 完成读取文件并且行被添加到第一个列表后被调用。

在第二种方法中,第一个列表用于创建第二个列表。完成所有操作后,第一个方法使用第二个列表。

这是我使用的代码,如果有不清楚的地方请询问,我会尽力提供所需的信息。

public synchronized void theBaseList() {
    Thread t = new Thread() {
        @override
        public void run() {
          try(
              while((line = br.readLine()) != null) {
                  firstList.add(line):
              }
          }
          nextMethod();
          currentObject = (Object[]) secondList.get(0); // throws an exception
          }
      }
  };
  t.start();

public synchronized void nextMethod() {
    Thread t1 = new Thread(){
        double objectListSize = calculateObjectListLength(firstList.size());
        @override
        public void run() {
          try {
              // create Objects
              secondList.add(objects);
            }
         }
      };
      t1.start();
}

当我在nextMethod() 中使用Thread 从第一个列表中的项目中创建一个新的对象list 时,我得到一个ArrayIndexOutOfBoundsException

线程“Thread-4”java.lang.IndexOutOfBoundsException 中的异常:索引:0,大小:0

我通过在第二种方法中不使用Thread 来避免这种情况,并且一切正常。

如果我确实使用了 2 个Threads 并同时使用了两个方法synchronized,它仍然会抛出异常。

是否有可能或者我应该通过在第二种方法中不使用Thread 来解决?我以为synchronized 是用来处理这类问题的。我不明白为什么它不起作用。

【问题讨论】:

  • 你的意思是“在单独的线程中运行方法时”?
  • @EJP 是的,第一个方法中的线程正在调用一个方法。
  • 这里似乎没有理由使用单独的线程。操作是串行的。 t1 依赖 t 完成第一个列表的填充,t 依赖 t1 添加到第二个列表。
  • @Radiodef 我这样做是因为那里还有一个进度条,如果不使用线程我无法让它更新进度。
  • @Radiodef 很好,因为它是串行的,我不明白为什么会出现问题。

标签: java multithreading synchronized


【解决方案1】:

假设您的方法定义在一个名为 Sample 的类中,并且您创建了一个实例 mySample。这似乎是您的代码正在执行的操作:

main thread calls mySample.theBaseList() and synchronizes by locking on mySample.
  theBaseList() defines thread1 and starts it.
  theBaseList() exits scope, thus unlocking on mySample.

thread1 reads in the lines of a file and adds them to list1 (these operations are not synchronized)
thread1 calls mySample.nextMethod()
mySample.nextMethod() synchronizes by locking on mySample
    nextMethod() defines thread2 and starts it.
    nextMethod() exits scope, thus unlocking on mySample.

* thread2 sets up list2 (these operations are not synchronized)
* thread1, having returned from nextMethod() reads from list2 (these operations are not synchronized)

最后两个操作是你的竞争条件的原因。

在您的情况下,使用同步方法可能过于粗粒度。更好的选择可能是在两个线程都操作的对象上进行同步,即 secondList。

nextMethod();
synchronized(secondList) {
    currentObject = (Object[]) secondList.get(0); // should no longer throw an exception
}

synchronized(secondList) {
    // create Objects
    secondList.add(objects);
}

编辑:

synchronized(secondList) {
    nextMethod();
    secondList.wait();
    currentObject = (Object[]) secondList.get(0); // should no longer throw an exception
}

synchronized(secondList) {
    // create Objects
    secondList.add(objects);
    secondList.notifyAll();
}

【讨论】:

  • 我不知道 synchronized 可以在方法声明的外部或在这种情况下在方法声明内部使用。
  • 这并不能解决问题。 t 在列表为空时仍然可以获取锁。
  • 啊,你是对的@Radiodef。 t 可以等到第二个列表被填充,或者不应该首先创建 t2。
  • @chiaboy 我会在早上试试这个,看看它是否有效。
  • 编辑代码 sn-p 应该可以解决@Radiodef 突出显示的问题。假设用例确实需要 2 个额外的线程。
猜你喜欢
  • 1970-01-01
  • 2020-08-23
  • 2013-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-06
  • 1970-01-01
相关资源
最近更新 更多