• 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
    ...
  • 相关阅读:
    六. 异常处理5.多重catch语句的使用
    六. 异常处理4.try和catch的使用
    六. 异常处理3.未被捕获的异常
    六. 异常处理2.异常类型
    对mysql数据库中字段为空的处理
    mysql 中实现多条数据同时更新
    java 用PDFBox 删除 PDF文件中的某一页
    java7 java MethodHandle解析
    【十四】jvm 性能调优实例
    【十三】jvm 性能调优工具之 jstack
  • 原文地址:https://www.cnblogs.com/gmhappy/p/11864087.html
Copyright © 2020-2023  润新知