多线程之间的对象共享

时间:2018-01-24 09:01:11

标签: java multithreading java-8

我的问题是:
假设我有

class Person{
    String name;
    int age;
}

2个线程T1,T2。 T1设置Person的name和T2设置age的人 条件是,如果存在NAME,则仅设置AGE else wait() 请协助如何使用Java解决此问题。

谢谢,
拉胡

2 个答案:

答案 0 :(得分:3)

您可以使用Condition同步两个线程。

在Person类

中添加ConditionReentrantLock
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和AgeThread
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();
    }

}

答案 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() + "}");
    }
}