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 可能出现浪费资源时间的问题