java 多线程间通信(一)

synchronized同步

package com.test7;

public class Run {

	public class MyObject {

		private int a;

		public MyObject(int a) {
			this.a = a;
		}

		synchronized public void methodA() {
			System.out.println("run methodA" + this.a);
			this.a = 10;
		}
	}

	public class ThreadA extends Thread {
		private MyObject object;

		public ThreadA(MyObject object) {
			this.object = object;
		}

		@Override
		public void run() {
			object.methodA();
		}
	}

	public class ThreadB extends Thread {

		private MyObject object;

		public ThreadB(MyObject object) {
			this.object = object;
		}

		// 省略构造方法
		@Override
		public void run() {
			object.methodA();
		}
	}

	public static void main(String[] args) {
		Run r = new Run();
		MyObject object = r.new MyObject(5);

		// 线程A与线程B 持有的是同一个对象:object
		ThreadA a = r.new ThreadA(object);
		ThreadB b = r.new ThreadB(object);

		a.start();
		b.start();
	}

}
run methodA5
run methodA10

多个线程需要访问同一个共享变量、方法,谁拿到了锁(获得了访问权限),谁就可以执行。

wait/notify机制

package com.test7;

import java.util.ArrayList;
import java.util.List;

public class Test {

	static public class MyList {
		private static List<Integer> list = new ArrayList<Integer>();

		public static void add(int i) {
			list.add(i);
		}

		public static int size() {
			return list.size();
		}
	}

	public class ThreadA extends Thread {

		private Object lock;

		public ThreadA(Object lock) {
			super();
			this.lock = lock;
		}

		@Override
		public void run() {
			try {
				synchronized (lock) {
					if (MyList.size() != 5) {
						System.out.println("wait begin "
								+ System.currentTimeMillis());
						lock.wait();
						System.out.println("Interruption!!!");
						lock.notify();
						lock.wait();
						System.out.println("wait end  "
								+ System.currentTimeMillis());
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public class ThreadB extends Thread {

		private Object lock;

		public ThreadB(Object lock) {
			super();
			this.lock = lock;
		}

		@Override
		public void run() {
			try {
				synchronized (lock) {
					for (int i = 0; i < 10; i++) {
						MyList.add(i);
						if (MyList.size() == 5) {
							lock.notify();
							System.out.println("已经发出了通知");
							lock.wait();
						}
						System.out.println("添加了" + (i + 1) + "个元素!");
						System.out.println(MyList.list.toString());
						Thread.sleep(1000);
					}
					lock.notify();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		try {
			Test t = new Test();
			Object lock = new Object();

			ThreadA a = t.new ThreadA(lock);
			a.start();

			Thread.sleep(50);

			ThreadB b = t.new ThreadB(lock);
			b.start();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
wait begin 1535596248129
添加了1个元素!
[0]
添加了2个元素!
[0, 1]
添加了3个元素!
[0, 1, 2]
添加了4个元素!
[0, 1, 2, 3]
已经发出了通知
Interruption!!!
添加了5个元素!
[0, 1, 2, 3, 4]
添加了6个元素!
[0, 1, 2, 3, 4, 5]
添加了7个元素!
[0, 1, 2, 3, 4, 5, 6]
添加了8个元素!
[0, 1, 2, 3, 4, 5, 6, 7]
添加了9个元素!
[0, 1, 2, 3, 4, 5, 6, 7, 8]
添加了10个元素!
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
wait end  1535596258180

线程A要等待某个条件满足时(list.size()==5),才执行操作。线程B则向list中添加元素,改变list 的size。

A,B之间如何通信的呢?也就是说,线程A如何知道 list.size() 已经为5了呢?

这里用到了Object类的 wait() 和 notify() 方法。

当条件未满足时(list.size() !=5),线程A调用wait() 放弃CPU,并进入阻塞状态。不像while轮询那样占用CPU资源。

当条件满足时,线程B调用 notify()通知 线程A,所谓通知线程A,就是唤醒线程A,并让它进入可运行状态。

这种方式的一个好处就是CPU的利用率提高了。

管道通信

管道流主要用来实现两个线程之间的二进制数据的传播,下面以PipedInputStream类和PipedOutputStream类为例,实现生产者-消费者:

package com.test7;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class PipeTest {
	/**
	 * 我们以数字替代产品 生产者每5秒提供5个产品,放入管道
	 */
	class MyProducer extends Thread {

		private PipedOutputStream outputStream;

		private int index = 0;

		public MyProducer(PipedOutputStream outputStream) {
			this.outputStream = outputStream;
		}

		@Override
		public void run() {
			while (true) {
				try {
					for (int i = 0; i < 5; i++) {
						index++;
						System.out.println("放入产品:" + index);
						outputStream.write(index);
					}
				} catch (IOException e) {
					e.printStackTrace();
				}

				try {
					Thread.sleep(5000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 消费者每0.5秒从管道中取1件产品,并打印剩余产品数量,并打印产品信息(以数字替代)
	 */
	class MyConsumer extends Thread {

		private PipedInputStream inputStream;

		public MyConsumer(PipedInputStream inputStream) {
			this.inputStream = inputStream;
		}

		@Override
		public void run() {
			while (true) {
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				try {
					int count = inputStream.available();
					if (count > 0) {
						System.out.println("剩余产品数量: " + count);
						System.out.println("得到产品: " + inputStream.read());
					} else {
						System.out.println("未取到产品");
					}
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}
	}

	public static void main(String[] args) {

		PipeTest t = new PipeTest();

		PipedOutputStream pos = new PipedOutputStream();
		PipedInputStream pis = new PipedInputStream();
		try {
			pis.connect(pos);
		} catch (IOException e) {
			e.printStackTrace();
		}

		t.new MyProducer(pos).start();
		t.new MyConsumer(pis).start();

	}
}
放入产品:1
放入产品:2
放入产品:3
放入产品:4
放入产品:5
剩余产品数量: 5
得到产品: 1
剩余产品数量: 4
得到产品: 2
剩余产品数量: 3
得到产品: 3
剩余产品数量: 2
得到产品: 4
剩余产品数量: 1
得到产品: 5
未取到产品
未取到产品
未取到产品
未取到产品
未取到产品
放入产品:6
放入产品:7
放入产品:8
放入产品:9
放入产品:10
剩余产品数量: 5
得到产品: 6
剩余产品数量: 4
得到产品: 7
剩余产品数量: 3
得到产品: 8
剩余产品数量: 2
得到产品: 9
剩余产品数量: 1
得到产品: 10
...

 

posted on 2018-08-30 10:52  疯狂的小萝卜头  阅读(132)  评论(0编辑  收藏  举报