rahulnikhare
rahulnikhare

Reputation: 1486

Object sharing between multiple threads

My question is :
Let say I have

class Person{
    String name;
    int age;
}

And 2 threads T1, T2. T1 sets name of Person and T2 sets age of person.
Condition is if NAME exist then only set AGE else wait().
Please assist how to solve this question using Java.

Thanks,
Rahul.

Upvotes: 0

Views: 129

Answers (2)

yegodm
yegodm

Reputation: 1044

You can achieve that with CompletableFuture. The code might not be the best with respect to performance but relatively short and simple to maintain:

public class Person {
    final CompletableFuture<String> name = new CompletableFuture<>();
    final CompletableFuture<Integer> age = new CompletableFuture<>();

    public void setName(String value) {
        System.out.println("Setting name to " + value);
        name.complete(value);
        System.out.println("Set name to " + value);
    }

    public void setAge(int value) {
        System.out.println("Setting age to " + value);
        // only set age when name is set, otherwise wait indefinitely
        name.thenRun(() -> {
            age.complete(value);
        }).join();
        System.out.println("Set age to " + value);
    }

    public String getName() {
        return name.join();
    }

    public Integer getAge() {
        return age.join();
    }

    private static void sleep(TimeUnit unit, int value) {
        try {
            Thread.sleep(unit.toMillis(value));
        }
        catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IllegalStateException("interrupted");
        }
    }

    static final ExecutorService executor = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws InterruptedException {

        test("Thomas Edison", 1, 171, 2);
        test("Elvis Presley", 2, 83, 1);
        executor.shutdown();
    }

    static void test(final String name, final int secondsBeforeNameSet,
                     final int age, final int secondsBeforeAgeSet) throws InterruptedException {
        final Person p = new Person();
        executor.invokeAll(Arrays.asList(
            Executors.callable(() -> {
                sleep(TimeUnit.SECONDS, secondsBeforeAgeSet);
                p.setAge(age);
            }),
            Executors.callable(() -> {
                sleep(TimeUnit.SECONDS, secondsBeforeNameSet);
                p.setName(name);
            })
        ));
        System.out.println("Person{ name:" + p.getName() + ", age:" + p.getAge() + "}");
    }
}

Upvotes: 2

xingbin
xingbin

Reputation: 28269

You can use a Condition syncronize two threads.

Add Condition and ReentrantLock in Person class

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Person {

    private ReentrantLock lock;
    private Condition nameCondition;
    private String name;
    private Integer age;

    public Person() {
        this.lock = new ReentrantLock();
        this.nameCondition = lock.newCondition();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Condition getNameCondition() {
        return nameCondition;
    }

    public ReentrantLock getLock() {
        return lock;
    }

}

NameThread set the name and signal:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class NameRunnable implements Runnable{

    private Person person;
    private String name;

    public NameRunnable(Person person, String name) {
        this.person = person;
        this.name = name;
    }

    @Override
    public void run() {
        ReentrantLock lock = person.getLock();
        Condition condition = person.getNameCondition();
        lock.lock();
        try {
            person.setName(name);
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
}

AgeThread wait until name has been set:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class AgeRunnable implements Runnable{

    private Person person;
    private Integer age;

    public AgeRunnable(Person person, Integer age) {
        this.person = person;
        this.age = age;
    }

    @Override
    public void run() {
        ReentrantLock lock = person.getLock();
        Condition condition = person.getNameCondition();
        lock.lock();
        try {
            while (person.getName() == null) {
                condition.await();
            }
            person.setAge(age);
        } catch (InterruptedException e) {
            // TODO
        } finally {
            lock.unlock();
        }
    }
}

In main thread start NameThread and AgeThread with parameters:

public class Main {

    public static void main(String[] args) throws InterruptedException {
        Person person = new Person();
        NameRunnable nameRunnable = new NameRunnable(person, "Test");
        AgeRunnable ageRunnable = new AgeRunnable(person, 10);
        new Thread(nameRunnable).start();
        new Thread(ageRunnable).start();
    }

}

Upvotes: 3

Related Questions