Java:跨多个线程共享变量

Java:跨多个线程共享变量,java,multithreading,synchronization,atomicity,Java,Multithreading,Synchronization,Atomicity,背景:我正在并行运行自动化测试。多个浏览器在相同数量的线程中启动,即1个浏览器是1个线程,使用pom.xml中的forking 下面的插件在pom.xml中创建与线程(分叉)计数相同数量的并行**IT.class。 所有这些类同时并行执行。因此,似乎每当我创建一个可变变量或原子整数时,每个线程都会创建自己的变量,因此跨多个线程共享一个变量的概念是行不通的 <plugin> <artifactId&g

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

下面的插件在
pom.xml
中创建与线程(分叉)计数相同数量的
并行**IT.class

所有这些类同时并行执行。因此,似乎每当我创建一个
可变变量
原子整数
时,每个线程都会创建自己的变量,因此跨多个线程共享一个变量的概念是行不通的

                <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>
尝试2:原子和同步

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();
            }
    };
AtomicInteger flag = new AtomicInteger(0);

    private EventHandler<TestRunStarted> prepareTestData = event -> {
        if(flag.get()==0) {
            System.out.println("Preparing test data");
            value.incrementAndGet();
        }
AtomicInteger标志=新的AtomicInteger(0);
私有EventHandler prepareTestData=事件->{
if(flag.get()==0){
System.out.println(“准备测试数据”);
value.incrementAndGet();
}

如果您执行一个测试(flag.get()==0)和一个操作,那么您有两个方法来同步这两件事。只需将整个prepareTestData方法标记为已同步?

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

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
}
volatile布尔标志=false;
public void setFlagTofalse(){
System.out.println(“内部同步块”);
this.flag=true;
}
//上课前只工作一次
private EventHandler prepareTestData=event->prepareData();
私有同步的void prepareData(){
如果(!标志){
System.out.println(“准备测试数据”);
setFlagTofalse();
}
//在此准备数据
}

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

编辑:更多解释

@保罗解释了锁的作用:它基本上是一个球,可以被线抛来抛去。因此,如果你和一群人坐成一个圆圈,你就有了这个球,那么轮到你谈论“X”然后,当你完成发言时,你把球放在圆圈中间,它一直留在那里,直到同一个人或其他人再次想要球,然后等待或等待直到它可用,然后再谈论“X”。在你的情况下,一个线程必须有一个锁来改变或读取变量标志,所以你要做的是:

Mutex lock = new Mutex();
lock.aquire();
if ( flag == something ){
    //do something
}
mutex.release()
或者如果您正在更改标志

lock.aquire();
flag = something;
lock.release();
正如您所见,锁是在线程之间共享的,因此它是在管理线程的类中创建的,并传递给线程中启动的可运行对象或方法

因此:

祝你好运:)

标记和锁定对象必须是“静态”的,这样每个对象只有一个实例。虽然如果你有单例对象,那么你不必对标记使用“静态”,但“锁定对象”应该是静态的

另外,在“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;
       }
   }
}


希望这能回答你的问题。

如果线程没有得到数据,它将无法通过测试。我不想这样。嘿,但是
互斥锁是我从来没有听说过的东西。如果你能分享这个片段,那将是一个很好的学习。@paul
互斥锁
不过是一个
…你的同步已经是一个互斥锁了在对象实例中@Eugene说的是真的,但有时我更喜欢看到实际使用的锁的方法。@BasvanderLinden这是哪个api,这是
import org.jruby.ext.thread.Mutex;
?@paul
import java.util.concurrent.Semaphore
,一个信号量类似于互斥锁,但你可以决定有多少线程可以访问ss锁。向下滚动到下面链接上的第2节。阅读:标志不需要是静态的。这取决于问题中未显示的上下文。而且你绝对不应该使用
布尔
而不是
布尔
@punit我不需要告诉其他线程像
线程那样等待。睡眠
或者这些线程将在ir own?他们将如何走出等待?我尝试了Sofo Gial的答案,但不起作用,可能是因为它没有静态概念。让我尝试使用静态。@MarkRotterVeel如答案中所述,如果每个线程都有自己的对象并调用准备好的数据,则标志必须是静态的。如果它是单线程,则它不是。您没有关于
Boolean
@paul java负责线程的排队。如果synchronized不起作用,那么让我编辑我的答案以使用基于对象的锁定。@punitiwan。是的,这不是排队或顺序,它是并行的。所有线程都是并行运行的。谢谢,非常感谢。@paul如果这不起作用,那么你需要用这并不意味着每个线程都有自己的
标志和/或自己的监视器来进行同步。@MarkRotteveel每次你发表评论时,它看起来都很有价值,但我无法理解。这次我也没有理解。@paul这表明你真的需要复习一下你的并发性和多线程知识。如果我知道为什么我会问你?如果我想温习/改进/学习我需要实施,当我们实施时,我们会陷入困境,当我们陷入困境时,我们会提出问题,当我们应该提出问题时,我们会想到可用的最佳论坛,我们就在这里。请用a更新您的问题。您对某些答案不起作用的各种评论表明某些上下文是错误的缺少。缺少什么上下文?我将尝试更新,请至少猜测一下。首先,包含这些标志和方法的类。它们是如何调用或启动的,等等。在多线程和并行执行的情况下,这是显而易见的,但让我把它放在问题描述中。这不明显,否则我不会问。所有answ
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;
       }
   }
}