如何防止java中的同步代码中以前发生的情况?
我只有一个同步方法。其目的是防止两个线程更新同一个表,这肯定会导致异常。我试图更新一个表,它的数据来自一个巨大的外部数据库。在更新我的表之前,我必须做一些过滤和清理,这需要很多时间。我创建了多个线程,以便可以划分任务并快速更新表。计划/设计是一个线程清理完数据后,它应该更新我的表,而其他线程仍在清理。然而,在我的示例代码中,线程正在覆盖这些值,因为关系发生在before之前。我不希望线程共享数据,我只希望它们在某些线程更新时不更新。如果您可以在下面的代码中看到,我已经创建了一个列表,我使用它来循环创建一个线程并传递列表中的每个数据。但是,结果是,线程1、4和5在同步方法中使用了相同的程序ID,而它们不应该使用。是否有人可以帮助防止这种情况,使每个线程在同步代码中都有一个唯一的Id 这是我的密码:如何防止java中的同步代码中以前发生的情况?,java,multithreading,synchronization,Java,Multithreading,Synchronization,我只有一个同步方法。其目的是防止两个线程更新同一个表,这肯定会导致异常。我试图更新一个表,它的数据来自一个巨大的外部数据库。在更新我的表之前,我必须做一些过滤和清理,这需要很多时间。我创建了多个线程,以便可以划分任务并快速更新表。计划/设计是一个线程清理完数据后,它应该更新我的表,而其他线程仍在清理。然而,在我的示例代码中,线程正在覆盖这些值,因为关系发生在before之前。我不希望线程共享数据,我只希望它们在某些线程更新时不更新。如果您可以在下面的代码中看到,我已经创建了一个列表,我使用它来循
public Class HomeController{
List<String> programList = new ArrayList<String>();
programList.add("xxx");
programList.add("yyy");
for(String programId: programList){
System.out.println("programId Controller is " + programId);
//for each program Id create a thread
runnable.setProgramId(programId);
taskExecutor.execute(runnable);
}
}
public class TestRunnable implements Runnable{
public void run(){
String threadName = Thread.currentThread().getName();
System.out.println("threadName and programId Runnable are " + threadName +"--"+ programId);
TestSynchronized testSynchronized = new TestSynchronized();
testSynchronized.updateTable(programId);
}
}
}
public class TestSynchronized{
private volatile boolean isLocked = false;
public synchronized void updateTable(String programId){
while(isLocked) {
try {
wait();
} catch (InterruptedException e) {}
}
isLocked=true;
String threadName = Thread.currentThread().getName();
System.out.println("threadName and programId Synchronized are " + threadName +"--"+ programId);
isLocked=false;
notify();
}
}
您有多少份
TestSynchronized
?如果它不止一个,您将无法获得任何同步
将同步与实际代码执行分开。您有多少份
TestSynchronized
的副本?如果它不止一个,您将无法获得任何同步
将同步与实际代码执行分开。您需要了解对象监视器是如何工作的<代码>同步将阻止对资源、对象引用的访问。在本例中,为每个线程创建一个新的
TestSynchronized
。由于同步工作在对象引用上,因此基本上不会在任何地方阻塞
如果创建一个
TestSynchronized
并将其传递给每个TestRunnable
,您将获得预期的输出。您需要了解对象监视器是如何工作的<代码>同步将阻止对资源、对象引用的访问。在本例中,为每个线程创建一个新的TestSynchronized
。由于同步工作在对象引用上,因此基本上不会在任何地方阻塞
如果创建一个
TestSynchronized
并将其传递给每个TestRunnable
,您将获得预期的输出。显示的代码中有两个问题:
TestRunnable
,这意味着programmaid
在使用之前会被覆盖(或可以被覆盖)TestSynchronized
,因此您根本没有线程安全性TestSynchronized
TestRunnable
。在构造函数中传递程序ID和共享的TestSynchronized
显示的代码中有两个问题:
TestRunnable
,这意味着programmaid
在使用之前会被覆盖(或可以被覆盖)TestSynchronized
,因此您根本没有线程安全性TestSynchronized
TestRunnable
。在构造函数中传递程序ID和共享的TestSynchronized
同步(o)
块发生在另一个线程在同一对象上同步o
之前。这就是为什么你知道如果线程A进入块,更新一些变量,然后离开块,然后线程B进入块;线程B保证查看变量中存储的线程A
但它没有告诉你的是:
它不会告诉您哪个线程将首先进入同步块。如果程序中的两个线程有可能同时在同一对象上尝试同步,那么就有了数据竞争。一条线会赢,另一条线会输,而且没有办法知道哪条线会赢
如果您的程序中存在数据竞争,并且哪个线程获胜很重要,那么您就有一个缺陷
您可以更改设计,使其与哪个线程获胜无关,也可以更改设计以使用某种更高级别的同步(队列、信号量、屏障等),以确保正确的线程获胜
…由于发生在关系之前,线程正在覆盖值
不是真的回答你的问题,但我认为你误解了“以前发生过”的含义
Java语言规范(JLS)使用短语“之前发生”来描述某些保证,您可以使用这些保证来推理程序的行为。例如,JLS表示在一个线程中保留同步(o)
块发生在另一个线程在同一对象上同步o
之前。这就是为什么你知道如果线程A进入块,更新一些变量,然后离开块,然后线程B进入块;线程B保证查看变量中存储的线程A
但这就是它的作用
programId Controller is 23022490857
programId Controller is 23022491963
threadName and programId Runnable are taskExecutor-1--23022490857
programId Controller is 23022492068
threadName and programId Runnable are taskExecutor-2--23022491963
programId Controller is 23022492300
threadName and programId Synchronized are taskExecutor-1--23022491963
programId Controller is 23022495561
threadName and programId Runnable are taskExecutor-3--23022492068
threadName and programId Synchronized are taskExecutor-2--23022492068
programId Controller is 38416827134
threadName and programId Synchronized are taskExecutor-3--23022492300
threadName and programId Runnable are taskExecutor-4--23022492300
threadName and programId Runnable are taskExecutor-1--38416827134
threadName and programId Synchronized are taskExecutor-1--38416827134
threadName and programId Runnable are taskExecutor-5--23022495561
threadName and programId Synchronized are taskExecutor-4--38416827134
threadName and programId Synchronized are taskExecutor-5--38416827134