导读:
1、设置对象和打印对象的线程,其实我们应该写得更加纯粹,避免耦合;
2、竞争资源是 Student ,所以同步的代码逻辑应该写在竞争资源的类中,这样更合理。

代码:
1、竞争资源类

public class Student {

    private String name;
    private Integer age;
    private Boolean flag=false;

    public synchronized void set(String name,Integer age){
        // 如果有数据,就等待
        if(this.flag){
            // 有数据,就等待
            // 唤醒以后继续往下执行
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 设置数据
        this.name = name;
        this.age = age;
        // 修改标记
        this.flag = true;
        this.notify();

    }

    public synchronized void get(){
        // 如果没有数据,就等待
        if(!this.flag){
            //
            try {
                // 被唤醒以后继续往下执行
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("name => " + name + ",age=> "+ age);
        // 修改标记
        this.flag=false;
        this.notify();
    }

}

2、设置对象和获取对象的线程

public class GetThread implements Runnable {

    private Student student;

    public GetThread(Student student){
        this.student = student;
    }

    @Override
    public void run() {
        while (true){
            student.get();
        }
    }
}
public class SetThread implements Runnable {

    private Student student;
    private Integer x=0;


    public SetThread(Student student){
        this.student = student;
    }

    @Override
    public void run() {
        while (true){
            if(x%2==0){
                student.set("liwei",29);
            }else {
                student.set("zhouguang",30);
            }
            x++;
        }
    }
}

3、测试代码

/**
 * Created by liwei on 16/7/19.
 * 把 Student 的成员变量私有化

 * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
 * 如何实现呢?
 *      通过Java提供的等待唤醒机制解决。
 *
 * 等待唤醒:
 *      Object类中提供了三个方法:
 *          wait():等待
 *          notify():唤醒单个线程
 *          notifyAll():唤醒所有线程
 *      为什么这些方法不定义在Thread类中呢?
 *          这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
 *          所以,这些方法必须定义在Object类中。
 *
 * 最终版代码中:
 *      把Student的成员变量给私有的了。
 *      把设置和获取的操作给封装成了功能,并加了同步。
 *      设置或者获取的线程里面只需要调用方法即可。
 */
public class StudentDemo {

    public static void main(String[] args) {
        Student student = new Student();
        GetThread getThread = new GetThread(student);
        SetThread setThread = new SetThread(student);
        Thread t1 = new Thread(getThread);
        Thread t2 = new Thread(setThread);
        t1.start();
        t2.start();
    }

}