Java:在多个线程之间共享变量

时间:2019-05-23 10:45:09

标签: java multithreading synchronization atomicity

背景:我正在并行运行自动化测试。多个浏览器在相同数量的线程中启动,即1个浏览器即1个线程,并使用pom.xml中的分支。

pom.xml中的插件在下面创建了与线程(叉)计数相等的Parallel**IT.class
所有这些类都一次并行执行。因此,似乎每当我创建volatile variableAtomicInteger时,每个线程都会创建自己的线程,因此在多个线程之间共享变量的概念不起作用。

                <plugin>
                        <artifactId>maven-failsafe-plugin</artifactId>
                        <version>${maven.failsafe.plugin}</version>
                        <configuration>
                            <systemPropertyVariables>
                                <webdriver.base.url>${webdriver.base.url}</webdriver.base.url>
                                                                </systemPropertyVariables>
                            <argLine>
                                -javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
                            </argLine>
                            <forkCount>5</forkCount>
                            <reuseForks>true</reuseForks>
                            <includes>
                                <include>**/Parallel*IT.class</include>
                            </includes>
                            <perCoreThreadCount>true</perCoreThreadCount>
                            <properties>
                                <property>
                                    <name>listener</name>
            <value>ru.yandex.qatools.allure.junit.AllureRunListener</value>
                                </property>
                            </properties>
                        </configuration>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>integration-test</goal>
                                    <goal>verify</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>


我只希望1个线程访问“准备测试数据”功能并将flag设置为false,而其他线程将flag视为false他们不会尝试准备测试数据。

我正在跟踪教程https://www.youtube.com/watch?v=WH5UvQJizH0,以使用synchronization变量实现volatile。也许我在犯一些错误,但是所有线程都在打印System.out.println("Preparing test data");

尝试1:不稳定和同步

volatile boolean flag = false;

    public synchronized void setFlagTofalse(){
        System.out.println("Inside sync block");
          this.flag = true;
    }
    // works before class only once
    private EventHandler<TestRunStarted> prepareTestData = event -> {
            if(flag==false) {
                System.out.println("Preparing test data");              
                setFlagTofalse();
            }
    };

尝试2:原子与同步

AtomicInteger flag = new AtomicInteger(0);

    private EventHandler<TestRunStarted> prepareTestData = event -> {
        if(flag.get()==0) {
            System.out.println("Preparing test data");
            value.incrementAndGet();
        }

4 个答案:

答案 0 :(得分:1)

如果您是我,则在访问标志变量时将实现互斥锁。因此,在读取标志的值或更改其值之前,线程必须获取锁。这样,他们永远不会同时读取它,也不会在读取旧值之前写入新值,等等。

编辑:更多说明

@paul解释锁的作用:基本上,它是一个可以被线程抛掷的球。因此,如果您与一群人围成一圈坐下,并且有球,那么该说“ X”了。然后,一旦您说完,就将球放在圆圈的中间,直到那里,直到同一个人或其他人再次想要球,然后接住球或等到球可用为止,然后再说“ X”。在您的情况下,线程必须具有锁才能更改或读取变量标志,因此您将要做的是:

Mutex lock = new Mutex();
lock.aquire();
if ( flag == something ){
    //do something
}
mutex.release()

或者如果您要更改标志。

lock.aquire();
flag = something;
lock.release();

如您所见,锁在线程之间共享。因此,它是在管理线程的类中创建的,然后传递给在线程中启动的Runnable对象或方法。

所以:

Mutex lock = new Mutex();
Runnable1 r1 = new Runnable1(lock);
Runnable2 r2 = new Runnable2(lock);
//use the lock in the methods of t1 and t2 that use your volitile var
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);

t1.start();
t2.start();

//the join wait for completion of the runnable method in your class.
t1.join();
t2.join();

祝你好运:)

答案 1 :(得分:0)

如果您进行测试(flag.get()== 0)和一个操作,则您将两个同步。只需将整个prepareTestData方法标记为同步

答案 2 :(得分:0)

您同步了错误的方法。您可以尝试这样的方法:

volatile boolean flag = false;

public void setFlagTofalse(){
    System.out.println("Inside sync block");
    this.flag = true;
}
// works before class only once
private EventHandler<TestRunStarted> prepareTestData = event -> prepareData();

private synchronized void prepareData() {
    if(!flag) {
        System.out.println("Preparing test data");
        setFlagTofalse();
    }
    //prepare data here
}

答案 3 :(得分:0)

“标志”和“ lockObject”必须为“静态”,以便每个对象只有一个实例。尽管如果您有单例对象,则不必为“标志”使用“静态”,但“ lockObject”应为静态。

此外,在“ prepareTestData”中使用“ lockObject”进行同步。这表明Java到此为止,只有一个线程可以访问该代码。一旦一个线程进入内部,其他线程将等待该线程返回后再进入。

private static Object lockObject = new Object();
private static Boolean flag = Boolean.FALSE;

private void prepareTestData() {
   synchronized(lockObject) { //This will keep other threads waiting
      if(!flag) {
          //prepare data
          flag = Boolean.TRUE;
       }
   }
}

希望这会回答您的问题。