Java 学习笔记 - 关于线程通讯的问题

创建一个基于对共享对象(包括名字和性别的对象ShareResource)

/**
 * Created by wojia on 2017/4/24.
 */
public class ShareResource {
    //创建 名字 性别
    private String name;
    private String gender;
    //这两个计数用来确定导致后面sleep后导致的性别紊乱问题
    int count1 = 0;
    int count2 = 0;
//privided for producer
    synchronized public void push(String name , String gender){
        this.name = name;
        //名字创建计数
        count1++;
        /**
        try {
            //调整这个时间长短有惊喜
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        */
        this.gender = gender;
        //性别创建计数
        count2++;
    }
    //provided for comsumer
    synchronized public void  pop(){
/**
        try {
            //调整这个时间长短有惊喜
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 */
        //输出性别 名字以及对应的计数
        System.out.println(this.name + count1 + "-" +this.gender + count2 );

    }

}

再创建一个编辑者(producer)和使用者(consumer)两个线程,同时操作同一个共享对象

public class Producer implements Runnable{
    //create a space for the ShareResource instance that input
    private ShareResource source = null;
    //复写其构造器 使得构建对象时对象里存了 公共存档的备份 进行 push 操作
    Producer(ShareResource source){
        this.source = source;
    }
    @Override
    public void run() {

        for (int i = 0 ; i < 50;i++){

            if (i % 2 == 0)
                source.push("xiulipig","male");
            else
            {
                source.push("karven","female");
            }
            try {
        //这个时间起到很大作用 Thread.sleep(
1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }

 

public class Consumer implements Runnable{
    //create a space for the ShareResource instance that input
    private ShareResource source = null;
    //override input a copy of class ShareResource
    Consumer(ShareResource source){
        this.source = source;
    }

    @Override
    public void run() {
        for (int i = 0 ; i < 50;i++) {
            source.pop();
            try {
      //这个时间也起到很大作用 Thread.sleep(
1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }

下面是主线程,两个Thread 

public class Test {
    public static void main(String args[]){
        //先创建共享对象
        ShareResource resource =new ShareResource();

        //create thread for producer
        new Thread(new Producer(resource)).start();
        new Thread(new Consumer(resource)).start();

    }
}

发现调整两个sleep时间一致可以试验两个人交替打印

但可以用到 Object(这里就是被同步监听 ,就是被producer 和 consumer所共享的对象) 的 notify ()和 wait()方法来实验实现!

public class ShareResource {
    //创建 名字 性别
    private String name;
    private String gender;
    private boolean isEmpty = true;
    //这两个计数用来确定导致后面sleep后导致的性别紊乱问题
    int count1 = 0;
    int count2 = 0;
//privided for producer
    synchronized public void push(String name , String gender)  {
        if (!isEmpty){
            //false 表示若不是空 就sleep 等待consumer来操作
            try {
                this.wait();/**release the ownership of the ShareResource's monitor */
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.name = name;
        //名字创建计数
        count1++;
        /**
        try {
            //调整这个时间长短有惊喜
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        */
        this.gender = gender;
        //性别创建计数
        count2++;
        isEmpty = false;
        //若producer没sleep 且执行完 赋值过程 此时应该sleep了
        this.notify();
        /*
        要理解 在这个虽然consumer被awakened
        但是 lock仍然在producer中 所以执行完这个statement后 this 还是指向 producer
        只有producer执行完push后结束后 consumer才有机会竞争lock
        */
        System.out.println(Thread.currentThread().getName());
        /**要深刻理解lock机制
         * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
         * The awakened thread will compete in the usual manner with any other threads that might be actively competing to
         * synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being
         * the next thread to lock this object.

         This method should only be called by a thread that is the owner of this object's monitor.
         A thread becomes the owner of the object's monitor in one of three ways:

         By executing a synchronized instance method of that object.
         By executing the body of a synchronized statement that synchronizes on the object.
         For objects of type Class, by executing a synchronized static method of that class.
         Only one thread at a time can own an object's monitor.
         * */

    }
    //provided for comsumer
    synchronized public void  pop()  {
/**
        try {
            //调整这个时间长短有惊喜
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 */
        if(isEmpty) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //输出性别 名字以及对应的计数
        System.out.println(this.name + count1 + "-" +this.gender + count2 );
        isEmpty = true;

            this.notify();
        
        }
    }

 //还有一种情况  上述只是为了说明 线程通讯而设置的,像上面的需求完全可以用 if flows 来达到  不过那样 两个线程一直没sleep 可能出现浪费资源时间的问题

posted on 2017-04-24 21:33  吸毒术士柯震东  阅读(297)  评论(1编辑  收藏  举报

导航