我的问题是:
假设我有
class Person{
String name;
int age;
}
2个线程T1,T2。 T1设置Person的name
和T2设置age
的人
条件是,如果存在NAME,则仅设置AGE else wait()
请协助如何使用Java解决此问题。
谢谢,
拉胡
答案 0 :(得分:3)
您可以使用Condition同步两个线程。
在Person类
中添加Condition
和ReentrantLock
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设置名称和信号:
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等到名字设置完毕后:
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();
}
}
}
在主线程中,使用参数:
启动NameThread和AgeThreadpublic 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();
}
}
答案 1 :(得分:2)
您可以使用CompletableFuture
实现这一目标。代码在性能方面可能不是最好的,但维护起来相对较短且简单:
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() + "}");
}
}