Обработка статических переменных в многопоточной Java-программе - PullRequest
0 голосов
/ 30 августа 2018

Ниже фабричный класс используется для получения драйверов для исполнения

public class DriverFactory {
    //holds the device config
    public static Map<String, String> devConfig = new ConcurrentHashMap<>();

    //other lines of code follow
}

Этот конфиг загружается в класс junit из внешнего источника данных, как показано ниже:

@RunWith(ConcurrentTestRunner.class)
public class MyTestRunner{
    static final int THREAD_COUNT = 1;

    @ThreadCount(THREAD_COUNT) @Override @Test
    public void run(){
        // Devices class returns config for the device
        DriverFactory.devConfig = Devices.getConfig()
        //other lines of code to perform execution
    }
}

Если во время выполнения требуется настройка устройства в другом классе, доступ к нему осуществляется следующим образом:

public class MobileActions{
    public void swipe(){
        String pf = DriverFactory.devConfig.get("Platform");
        //other lines of code
    }
}

Этот подход (имеющий devConfig в качестве статического) отлично работает, есть один поток. Теперь, чтобы поддержать параллельное выполнение на устройстве, если число потоков изменено на 2, devConfig всегда будет иметь значение, установленное 2-м потоком.

Чтобы избежать этой проблемы, если devConfig сделан нестатичным, мы должны внедрить эту переменную во все другие классы, например, в вышеупомянутый класс MobileActions. Есть ли способ, что эта переменная может оставаться статической, но все еще работать во время многопоточного выполнения (каждый поток должен иметь дело со своей собственной копией devConfig). Мы также попытались сделать эту переменную как ThreadLocal <>, но это тоже не помогло.

Любая помощь очень ценится! Спасибо

Ответы [ 3 ]

0 голосов
/ 30 августа 2018

Вы можете заключить свой devConfig в ConcurrentHashMap:

public class DriverFactory {
    //holds the device config
    private static final String CONFIG_KEY = "config_key";
    private static final ConcurrentHashMap<String, Map<String, String>> devConfig = new ConcurrentHashMap<>();

    public static Map<String, String> setDevConfig(Map<String, String> devConfig) {
        return DriverFactory.devConfig.putIfAbsent(CONFIG_KEY, devConfig);
    }

    public static Map<String, String> getDevConfig() {
        return DriverFactory.devConfig.get(CONFIG_KEY);
    }

    //other lines of code follow
}

@RunWith(ConcurrentTestRunner.class)
public class MyTestRunner{
    static final int THREAD_COUNT = 1;

    @ThreadCount(THREAD_COUNT) @Override @Test
    public void run(){
        // Devices class returns config for the device
        DriverFactory.setDevConfig(Devices.getConfig())
        //other lines of code to perform execution
    }
}

public class MobileActions{
    public void swipe(){
        String pf = DriverFactory.getDevConfig().get("Platform");
        //other lines of code
    }
}

Но если вы хотите выполнить Devices.getConfig() один раз, попробуйте java.util.concurrent.ConcurrentHashMap#computeIfAbsent или пользовательскую блокировку. Что-то вроде:

    public static Map<String, String> getDevConfig() {
        return DriverFactory.devConfig
                .computeIfAbsent(CONFIG_KEY, s -> Devices.getConfig());
    }
0 голосов
/ 31 августа 2018

Наконец-то нашел способ по этой ссылке:

https://dmitrykrivenko.blogspot.com/2016/07/threadlocal-and-inheritablethreadlocal.html

Использовал InheritableThreadLocal вместо ThreadLocal. Таким образом, теперь я могу получить доступ к данным в дочерних потоках.

public class DriverFactory {

private static final ThreadLocal<Map<String, String>> driverData = new InheritableThreadLocal<>();


public static String getDriverData(String key){
    return driverData.get().get(key);
}   

public static void setDriverData(Map<String, String> driver){
    driverData.set(driver);
}

}

0 голосов
/ 30 августа 2018

Сделайте devConfig в DriverFactory приватным. Предоставить добытчики и установщики к нему. Если вам нужно, чтобы он был специфичным для потока, сделайте его локальным.

public class DriverFactory {

    // holds the device config
    private static final ThreadLocal<Map<String, String>> devConfig = ThreadLocal
        .withInitial(ConcurrentHashMap::new);

    public static String getDevConfig(String key) {
        return this.devConfig.get().get(key);
    }

    public static void setDevConfig(Map<String, String> config) {
        this.devConfig.get().putAll(config);
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...