Защита синхронизации не работает для двойных потоков
Ниже мой урезанный код Java для обзора. У меня есть несколько подклассов, и когда вызывается execParallel (), запускается новый поток. Этот поток и поток по умолчанию должны несколько раз выполнить ualCritFunction() через actionFunction(), но эта функция будет правильно работать только для данного соединения SubClassC, если одновременно выполняется только одним процессом.
Я использовал ключевое слово "synchronized" для защиты от одновременных выполнений, однако на практике критическая функция () фактически вызывается обоими потоками одновременно.
Есть идеи, что я делаю не так?
public class MainClass extends GlobalLibrary {
public static SubClassA masterObj;
public MainClass() {
masterObj = new SubClassA();
}
public static class SubClassA {
public SubClassB subObj1;
public SubClassB subObj2;
public SubClassA() {
subObj1 = new SubClassB();
subObj2 = new SubClassB();
}
}
public static class SubClassB {
public SubClassC conObj;
public Thread ut = null;
public SubClassB() {
conObj = new SubClassC();
}
}
public static class SubClassC {
public TCPMasterConnection con=null;
public SubClassC() {
con = new TCPMasterConnection();
}
public synchronized Object criticalFunction(int arg) {
return otherClass.executeCritical(con, arg);
}
}
public boolean actionFunction(SubClassB subObj, int arg) {
return (subObj.conObj.criticalFunction(arg)==null);
}
public class ActionThread implements Runnable {
public SubClassB subObj;
private int icode;
public ActionThread(SubClassB arg1, int arg2) {
subObj = arg1;
icode = arg2;
}
public void run() {
for (int i=0; i<10; i++) actionFunction(subObj, icode);
}
}
public void execParallel() {
masterObj.subObj1.ut = new Thread(new ActionThread(masterObj.subObj1, 1));
masterObj.subObj1.ut.start();
actionFunction(masterObj.subObj1, 2);
actionFunction(masterObj.subObj1, 3);
actionFunction(masterObj.subObj1, 4);
actionFunction(masterObj.subObj1, 5);
actionFunction(masterObj.subObj1, 6);
}
}
3 ответа
Если ваша цель - защитить otherClass.executeCritical(con, arg)
вызов, то вы хотите заблокировать на гранулярность otherClass
пример. Если цель состоит в том, чтобы в определенный момент времени использовать только один поток, использующий "мастер-соединение", что, по-видимому, было бы именно тем, чего вы очень хотите, то вам нужно, чтобы степень детализации блокировки была в моменте TCPMasterConnection
, В последнем случае ваш код будет выглядеть так:
public Object criticalFunction(int arg) {
synchronized(con) {
return otherClass.executeCritical(con, arg);
}
}
Теперь, если у вас есть многопоточный небезопасный код в обоих otherClass
а также con
(из TCPMasterConnection), вам может понадобиться блокировка с большей детализацией. В этом случае проще всего заблокировать на уровне класса, как описано в других ответах.
Является ли частью вашего кода, который вы хотите синхронизировать, сделайте это вместо этого:
Object lock = new Object();
public void doSomething{
synchronized(lock){
//your code
}
}
Synchronized methods
работать только на уровне экземпляра.
Вы вызываете критическую функцию () для разных экземпляров, поэтому они используют разные блокировки. Вы должны разделить блокировку между всеми экземплярами.
Попробуй это
public Object criticalFunction(int arg) {
synchronized (SubClassC.class) {
return otherClass.executeCritical(con, arg);
}
}