java并发数据结构与java并发协作控制

1 (1) 常用的数据结构是不安全的:
- ArrayList HashMap HashSet是非同步的
- 多个线程读写可能会抛出异常和错误
(2) 传统的vector,hashTable等同步集合性能过差
(3) 并发数据结构数据的添加和删除
- 阻塞式集合:当集合为空或者为满时,等待
- 非阻塞式集合:当集合为空或者为满时,不等待,返回null或者异常
(4) 所以高并发中,为了保证数据的一致性,此处应该用Collections中的方法
List list = Collections.synchronizedList(new ArrayList());
Set s = Collections.synchronizedSet(new HashSet());
Map m = Collections.synchronizedMap(new HashMap());
2 并发协作控制
(1) Thread/Excutor/Fork-join
-线程启动,运行,结束
- 线程之间缺少协作
(2) synchronized同步
- 限定只有一个线程才能进入关键区
- 简单粗暴,性能损失有点大
(3) Lock锁,也可以实现与synchronized一模一样的功能。
-且它可以实现更复杂的临界区结构,
-tryLock方法可以判断锁是否空闲
-允许分离读写的操作,多个读,一个写
-性能更好
(4) ReentrantLock类,可重入的互斥锁
(5) ReentrantLock类,可重入的读写锁
(6) lock和unLock函数
3 代码单例:
有家奶茶店,点单有时需要排队,假设想买奶茶的人如果看到需要排队,就决定不买

  public class LockExample {
     private static final ReentrantLock queueLock = new ReentrantLock(); //可重入锁
   public static void main(String[] args) throws InterruptedException {
		buyMilkTea();
	}
	public static void buyMilkTea() throws InterruptedException {
		LockExample lockExample = new LockExample();

		int STUDENTS_CNT = 10;
		//创建一个学生线程组,这个线程组中有10个匿名线程
		Thread[] students = new Thread[STUDENTS_CNT];
		for (int i = 0; i < STUDENTS_CNT; i++) {
			//分别启动这10个线程,去执行买奶茶这个动作
			students[i] = new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						long walkingTime = (long) (Math.random() * 1000);
						Thread.sleep(walkingTime);
						lockExample.tryToBuyMilkTea();
					} catch(InterruptedException e) {
						System.out.println(e.getMessage());
					}
				}
				
			}
			);	
			students[i].start();
		}
		for (int i = 0; i < STUDENTS_CNT; i++)
			students[i].join();
	}
}
  public void tryToBuyMilkTea() throws InterruptedException {
		//温馨提示:调用了tryLock之后一定要调用unlock方法
		boolean flag = true;
		while(flag)
		{   //queueLock为可重入锁,如果当前线程进来试着加锁,如果资源被别人占用,直接会返回让你等待
			if (queueLock.tryLock()) {
				//queueLock.lock();
				long thinkingTime = (long) (Math.random() * 500);
				Thread.sleep(thinkingTime);
				System.out.println(Thread.currentThread().getName() + ": 来一杯珍珠奶茶,不要珍珠");
				//卖完奶茶之后要解锁离开,不能一直占用资源
				flag = false;
				queueLock.unlock();
			} else {
				//System.out.println(Thread.currentThread().getName() + ":" + queueLock.getQueueLength() + "人在排队");
				System.out.println(Thread.currentThread().getName() + ": 再等等");
			}
			//如果flag等于true,睡眠一秒钟再去看一看资源是否已经被释放
			if(flag)
			{
				Thread.sleep(1000);
			}
		}
		
	}

可重入读写锁,假设奶茶店中有一名老板和多名员工,老板负责写订单,员工负责查看订单并且制作奶茶,老板写订单的时候员工不能查看订单,多个员工可以同时查看订单本,员工查看订单时老板不能新增订单.

  public class LockExample {
	private static final ReentrantReadWriteLock orderLock = new ReentrantReadWriteLock(); //可重入读写锁
		public static void main(String[] args) throws InterruptedException {
		handleOrder(); //需手动关闭
	}
	public static void handleOrder() throws InterruptedException {
		LockExample lockExample = new LockExample();
		
		//新建一个老板线程,并且启动此线程
		Thread boss = new Thread(new Runnable() {

			@Override
			public void run() {
				while (true) {
					try {
						lockExample.addOrder();
						long waitingTime = (long) (Math.random() * 1000);
						Thread.sleep(waitingTime);
					} catch (InterruptedException e) {
						System.out.println(e.getMessage());
					}
				}
			}
		});
		boss.start();
        //新建3个员工线程
		int workerCnt = 3;
		Thread[] workers = new Thread[workerCnt];
		for (int i = 0; i < workerCnt; i++)
		{   //并且启动这三个线程
			workers[i] = new Thread(new Runnable() {

				@Override
				public void run() {
					while (true) {
						try {
								lockExample.viewOrder();
								long workingTime = (long) (Math.random() * 5000);
								Thread.sleep(workingTime);
							} catch (InterruptedException e) {
								System.out.println(e.getMessage());
							}
						}
				}
				
			});
			
			workers[i].start();
		}
		
	}
}
	public void addOrder() throws InterruptedException {
		//写订单之前,先锁住此资源
		orderLock.writeLock().lock();
		long writingTime = (long) (Math.random() * 1000);
		Thread.sleep(writingTime);
		System.out.println("老板新加一笔订单");
		//释放锁
		orderLock.writeLock().unlock();
	}
	public void viewOrder() throws InterruptedException {
	    //查看订单之前所住此资源
		orderLock.readLock().lock();
			
		long readingTime = (long) (Math.random() * 500);
		Thread.sleep(readingTime);
		System.out.println(Thread.currentThread().getName() + ": 查看订单本");
		orderLock.readLock().unlock();			
      //查看完成之后释放锁
	}

4 semaphore
(1)信号量:本质上是一个计数器
计数器大于0可以使用,等于0不能使用
可以设置多个并发量,例如限制10个访问
(2)seamphore
-acquire 获取 信号量减1
- release释放 信号量加一
(3) 比lock更进一步,可以同时访问多个关键区
代码案例:停车场

public class SemaphoreExample {
   //创建5个信号源,表示只有5辆车可以执行停车这个动作,如果placeSemaphore等于0,则线程等待
	private final Semaphore placeSemaphore = new Semaphore(5);
   
	/**
	 * 现有一地下车库,共有车位5个,由10辆车需要停放,每次停放时,去申请信号量
	 * @param args
	 * @throws InterruptedException 
	 */
	public static void main(String[] args) throws InterruptedException {
		int tryToParkCnt = 10;

		SemaphoreExample semaphoreExample = new SemaphoreExample();
		//新建一个线程组,创建10个匿名线程去执行停车任务
		Thread[] parkers = new Thread[tryToParkCnt];
		
		for (int i = 0; i < tryToParkCnt; i++) {
			parkers[i] = new Thread(new Runnable() {

				@Override
				public void run() {
					try {
						long randomTime = (long) (Math.random() * 1000);
						Thread.sleep(randomTime);
						if (semaphoreExample.parking()) {
							long parkingTime = (long) (Math.random() * 1200);
							Thread.sleep(parkingTime);
							semaphoreExample.leaving();
						}
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
			
			parkers[i].start();
		}

		for (int i = 0; i < tryToParkCnt; i++) {
			parkers[i].join();
		}	
	}
	public boolean parking() throws InterruptedException {
		//如果申请到信号量表示停车成功,停车成功信号量减去1
		if (placeSemaphore.tryAcquire()) {
			System.out.println(Thread.currentThread().getName() + ": 停车成功");
			return true;
		} else {
			System.out.println(Thread.currentThread().getName() + ": 没有空位");
			return false;
		}

	}
	public void leaving() throws InterruptedException {
		//释放信号量,使信号量加1
		placeSemaphore.release();
		System.out.println(Thread.currentThread().getName() + ": 开走");
	}
}

5 Latch
(1)等待锁,是一个同步辅助类
(2)用来同步执行任务的一个或者多个线程
(3)不是用来保护临界区或者共享资源的
-countDown()计数减1
- await()等待latch变成0
(4) 代码案例

     public class CountDownLatchExample {

  /**
   * 设想百米赛跑比赛 发令枪发出信号后选手开始跑,全部选手跑到终点后比赛结束
   * 
   * @param args
   * @throws InterruptedException
   */
  public static void main(String[] args) throws InterruptedException {
  	int runnerCnt = 10;
  	CountDownLatch startSignal = new CountDownLatch(1);
  	CountDownLatch doneSignal = new CountDownLatch(runnerCnt);
      
  	for (int i = 0; i < runnerCnt; ++i) // create and start threads
  		new Thread(new Worker(startSignal, doneSignal)).start();

  	System.out.println("准备工作...");
  	System.out.println("准备工作就绪");
  	startSignal.countDown(); // let all threads proceed
  	System.out.println("比赛开始");
  	doneSignal.await(); // wait for all to finish
  	System.out.println("比赛结束");
  }

  static class Worker implements Runnable {
  	private final CountDownLatch startSignal;
  	private final CountDownLatch doneSignal;

  	Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
  		this.startSignal = startSignal;
  		this.doneSignal = doneSignal;
  	}

  	public void run() {
  		try {
  			startSignal.await();
  			doWork();
  			doneSignal.countDown();
  		} catch (InterruptedException ex) {
  		} // return;
  	}

  	void doWork() {
  		System.out.println(Thread.currentThread().getName() + ": 跑完全程");
  	}
  }

6 线程之间进行数据交换
(1) 允许并发线程中相互交换消息
(2) 允许在两个线程中定义同步点,当两个线程都达到同步点,他们交换数据结构
(3) Exchanger
- exchanger(),线程双发相互交互数据
- 交互数据是双向的
(4) 代码案例:



import java.util.Scanner;
import java.util.concurrent.Exchanger;

public class ExchangerExample {
	
	/**
	 * 本例通过Exchanger实现学生成绩查询,简单线程间数据的交换
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {
		Exchanger<String> exchanger = new Exchanger<String>();
		BackgroundWorker worker = new BackgroundWorker(exchanger);
		new Thread(worker).start();
		
		Scanner scanner = new Scanner(System.in);
		while(true) {
			System.out.println("输入要查询的属性学生姓名:");
			String input = scanner.nextLine().trim();
			exchanger.exchange(input); //把用户输入传递给线程
			String value = exchanger.exchange(null); //拿到线程反馈结果
			if ("exit".equals(value)) {
				break;
			}
			System.out.println("查询结果:" + value);
		}
		scanner.close();
	} 
}

class BackgroundWorker implements Runnable {

	final Exchanger<String> exchanger;
	BackgroundWorker(Exchanger<String> exchanger) {
		this.exchanger = exchanger;
	}
	@Override
	public void run() {
		while (true) {
			try {
				String item = exchanger.exchange(null);
				switch (item) {
				case "zhangsan": 
					exchanger.exchange("90");
					break;
				case "lisi":
					exchanger.exchange("80");
					break;
				case "wangwu":
					exchanger.exchange("70");
					break;
				case "exit":
					exchanger.exchange("exit");
					return;
				default:
					exchanger.exchange("查无此人");
				}					
			} catch (InterruptedException e) {
				e.printStackTrace();
			}				
		}
	}		
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值