Java多线程并发笔记05

示例程序1:volatile List 属性多线程操作

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

/**
 * 使用volatile关键字使得多个线程操作同一个
 * 2个线程,
 * 	一个线程不断往集合里添加元素
 * 	一个线程监听集合的元素个数
 * 		当个数等于某个数值时停止此线程
 * 		while(true)监听,性能不好,待改进
 * @author Administrator
 *
 */
public class ListAdd01 {
	
	/*volatile关键字修饰下才能在多个线程之间共享成员变量,要不然每个线程的方法体中都是当前成员变量的一个副本(在方法体中)*/
	private  static volatile List<String> list = new ArrayList<String>();
	
	public void add() {
		list.add("bjsxt");
	}
	
	public int size(){
		return list.size();
	}
	
	public static void main(String[] args) {
		final ListAdd01 list1 = new ListAdd01();
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					for(int i = 0; i < 10; i++) {
						list1.add();
						System.out.println("当前线程:"+ Thread.currentThread().getName() + "添加了一个元素...");
						Thread.sleep(100);
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		},"t1");
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				/*以这样的方式在这里等待需要消耗太多的系统资源,不推荐*/
				while(true) {
					if(list1.size() == 5) {
						System.out.println("当前线程:"+ Thread.currentThread().getName() + "收到了一个通知,listSize = 5线程停止...");
						throw new RuntimeException();
					}
				}
			}
		},"t2");
		
		t1.start();
		t2.start();
	}
}

示例程序2: 一线程监听,被唤醒,触发用计数器要优于wait,notify,因为notify不释放锁

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * wait、notify方法,wait释放锁,notify不释放锁
 * 
 * 
 * 采用wait,notify的输出结果
t2进入...
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
已经发出通知:notify
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t2收到了一个通知,listSize = 5线程停止...
Exception in thread "t2" java.lang.RuntimeException
	at com.bjsxt.thread.ListAdd02$2.run(ListAdd02.java:62)
	at java.lang.Thread.run(Thread.java:745)

直到最后一刻才输出,所以这种方式无法及时被执行

那怎么办呢?
用CountDownLatch:计数器,是一个阻塞flag,和同步不同步没关系,和锁没有任何关系
多用于远程链接的实现,比如zookeeper客户端调用远程连接(举得小例子)

 *
 */
public class ListAdd02 {
	public volatile List<String> list = new ArrayList<String>();
	
	void add(){
		list.add("bjsxt");
	}
	
	public int size() {
		return list.size();
	}
	
	public static void main(String[] args) {
		final ListAdd02 list2 = new ListAdd02();
		
		//实例化一个lock
		//当使用wait和notify的时候,一定要配合着synchronized使用
		final Object lock = new Object();
		final CountDownLatch count = new CountDownLatch(1);
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					//不要放到for循环外,等到天荒地老啊,若是放到for循环里面就更细粒度了,没问题(待测)。
					//若是这里的目的仅仅是保证10次for循环的原子性,那用synchronized完全OK,没问题,
					//但若目的是为了通知另外一个进程,并使另外的接到统治的 进程即时处理,则不适宜用synchronized。
//					synchronized (lock) {
						for(int i = 0; i < 10; i++) {
							list2.add();
							System.out.println("当前线程:"+ Thread.currentThread().getName() + " 添加了一个元素");
							Thread.sleep(500);
							if(list2.size() == 5) {
								System.out.println("已经发出通知:notify"); 
								//notify虽然通知了,但是并没有释放锁,
								//所以lock.wait()那里收到通知了也继续执行了,但因为锁被notify这占据着,所以线程被阻塞了,卡在那了
								//只要等到notify()的线程执行完毕释放了锁后,wait()重新获取到了锁后才能继续执行下去,不被卡住
//								lock.notify();
								count.countDown();
							}
						}
//					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		},"t1");
		
		
		
		/**
		 * 监听等待,
		 */
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
//				synchronized (lock) {
					if(list2.size() != 5) {
						try {
							System.out.println("t2进入...");
//							lock.wait();//等待并且释放锁
							count.await();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println("当前线程:"+ Thread.currentThread().getName() + "收到了一个通知,listSize = 5线程停止...");
						throw new RuntimeException();
					}
//				}
			}
		},"t2");
		
		t2.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t1.start();
		
	}
}
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 我的模拟队列
 * @author Administrator
 *
 */
public class MyQueue {
	//队列
	LinkedList<Object> list = new LinkedList<Object>();
	
	//计数器
	private AtomicInteger count = new AtomicInteger(0);
	
	//同步锁
	private Object lock = new Object();
	
	
	private final int minSize = 0; 
	
	private final int maxSize;
	
	public MyQueue(int maxSize){
		this.maxSize = maxSize;
	}
	
	public void add(Object obj){
		synchronized(lock) {
			try {
				while(count.get() == maxSize) {
					lock.wait();
				}
				//加入元素
				list.add(obj);
				//计数器加1
				count.incrementAndGet();
				
				//唤醒另外一个线程
				lock.notify();
				System.out.println("新插入的元素为:" + obj);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	public Object take() {
		synchronized(lock) {
			Object firstInObject = null;
			try {
				while(count.get() == minSize){
					lock.wait();
				}
				
				//数量减减
				firstInObject = list.removeFirst();
				//计数器减1
				count.decrementAndGet();
				//通知另外一个线程(唤醒)
				lock.notify();
				System.out.println("拿出的元素为:" + firstInObject);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return firstInObject;
		}
	}
	
	public int size() {
		return count.get();
	}
	
	public static void main(String[] args) {
		final MyQueue queue = new MyQueue(5);
		//插入5个元素,已满
		queue.add("a");
		queue.add("b");
		queue.add("c");
		queue.add("d");
		queue.add("e");
		
		System.out.println("当前容量长度为:" + queue.size());
		
		//再次插入,阻塞
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				queue.add("f");
				queue.add("g");
			}
		},"t1");
		t1.start();//t1的执行结果在t2之后,因为已经满了,被阻塞了,
	
		//拿出
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i = 0; i<3; i++) {
					queue.take();
				}
			}
		},"t2");
		
		//隔3秒再拿出
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t2.start();
	}
}

猜你喜欢

转载自blog.csdn.net/guchunchao/article/details/81635414