Reputation: 1486
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
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
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