Java并发包&并发队列

1. 同步容器类

1.1 Vector与ArrayList区别

1、ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适
     合随机查找、修改和遍历,不适合插入和删除。
2、Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,线程是安全的。

1.2 HasTable与HasMap区别

1、HashMap不是线程安全的,不能包含重复键,但可以包含重复值.HashMap允许null key和null value,
     而Hashtable不允许。
2、HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey

1.3 synchronizedMap

Collections.synchronized*(m) 将线程不安全的集合变为线程安全的集合

1.4 ConcurrentHashMap原理

      ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的HashTable,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。把一个整体分成了16个段(Segment.也就是最高支持16个线程的并发修改操作。这也是在重线程场景时减小锁的粒度从而降低锁竞争的一种方案。并且代码中大多共享变量使用volatile关键字声明,目的是第一时间获取修改的内容,性能非常好

2. 并发包三种计数器

2.1 CountDownLatch

       CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。countDownLatch的值一定是大于等于0。

代码01 CountDownLatch实现计数器功能:src/com/mysoft/demo01/CountDownLatchDemo.java

package com.mysoft.demo01;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
	public static void main(String[] args) throws InterruptedException {
		//初始化countDownLatch为2
		CountDownLatch countDownLatch=new CountDownLatch(2);
		new Thread(new Runnable() {			
			@Override
			public void run() {
				System.out.println("子线程,"+Thread.currentThread().getName()+":执行完毕");
				countDownLatch.countDown();  //每次countDownLatch的数值-1
			}
		},"thread-01").start();
		
		new Thread(new Runnable() {			
			@Override
			public void run() {
				System.out.println("子线程,"+Thread.currentThread().getName()+":执行完毕");
				countDownLatch.countDown();  //每次countDownLatch的数值-1
			}
		},"thread-02").start();
		countDownLatch.await();      //调用当前方法主线程阻塞  countDown结果为0, 阻塞变为运行状态
		System.out.println("两个子线程执行完毕.....");
		System.out.println("主线程继续执行.....");
	}
}

2.2 CyclicBarrier

      CyclicBarrier初始化时规定一个数目(int parties)表示调用了CyclicBarrier.await()进入等待的线程数。当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续。CyclicBarrier初始时还可带一个Runnable的参数,当给定数量的线程(线程)等待时,它将跳闸,当屏障跳闸时执行给定的屏障动作,由最后一个进入屏障的线程执行。

代码02 CyclicBarrier案例:/thread04/src/com/mysoft/demo01/CyclicBarrierDemo.java

package com.mysoft.demo02;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

class Write extends Thread{
	CyclicBarrier cyclicBarrier;
	
	public Write(CyclicBarrier cyclicBarrier){
		this.cyclicBarrier=cyclicBarrier;
	}
	
	@Override
	public void run() {
		System.out.println(getName()+",开始执行...");
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(getName()+",执行完毕...");
		
		try {
			//等待线程数达到规定值
			cyclicBarrier.await();
		} catch (InterruptedException | BrokenBarrierException e) {
			e.printStackTrace();
		}
		System.out.println("所有线程执行完毕......");
	}
}

public class CyclicBarrierDemo {
	public static void main(String[] args) {
		CyclicBarrier cyclicBarrier=new CyclicBarrier(5);
		for (int i = 0; i < 5; i++) {
			new Write(cyclicBarrier).start();
		}
	}
}

2.3 Semaphore信号量

      Semaphore是一种基于计数的信号量。它可以设定一个阈值,基于此,多个线程竞争获取许可信号,做自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞。Semaphore可以用来构建一些对象池,资源池之类的,比如数据库连接池,我们也可以创建计数为1的Semaphore,将其作为一种类似互斥锁的机制,这也叫二元信号量,表示两种互斥状态

semaphore.availablePermits();   //函数用来获取当前可用的资源数量
semaphore.acquire();       //申请资源
semaphore.release();       // 释放资源

代码03 Semaphore信号量案例:/thread04/src/com/mysoft/demo03/SemaphoreDemo.java

package com.mysoft.demo03;

import java.util.Random;
import java.util.concurrent.Semaphore;

class Parent extends Thread{	
	
	Semaphore wc;
	String name;
	
	public Parent(Semaphore wc,String name) {
		this.wc=wc;
		this.name=name;
	}
	
	@Override
	public void run() {
		//wc.availablePermits()获取当前资源数
		if(wc.availablePermits()>0) {
			System.out.println(name+"太好了,有座位了...");
		}else {
			System.out.println(name+"怎么没有座位了...");
		}
		try {
			//申请资源,如果没有资源就等待其它线程释放资源
			wc.acquire();
			//申请到资源后,执行
			System.out.println(name+"哈哈哈,抢到座位了...");
			Thread.sleep(new Random().nextInt(1000));
			System.out.println(name+"下车了...");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally {
			//释放资源
			wc.release();
		}
	}
}

public class SemaphoreDemo {

	public static void main(String[] args) {
		Semaphore semaphore=new Semaphore(3);
		for (int i = 1; i < 11; i++) {
			new Parent(semaphore, "第"+i+"个人说: ").start();
		}
	}
}

3. 并发队列

       在并发队列上JDK提供了两套实现,一个是以ConcurrentLinkedQueue为代表的高性能队列,一个是以BlockingQueue接口为代表的阻塞队列,无论哪种都继承自Queue

3.1 ConcurrentLinkedQueue

       是一个适用于高并发场景下的队列,通过无锁的方式,实现了高并发状态下的高性能,通常ConcurrentLinkedQueue性能好于BlockingQueue.它是一个基于链接节点的无界线程安全队列。该队列的元素遵循先进先出的原则。头是最先加入的,尾是最近加入的,该队列不允许null元素

3.2 BlockingQueue

3.2.1 ArrayBlockingQueue

       ArrayBlockingQueue:是一个有边界的阻塞队列,它的内部实现是一个数组。有边界的意思是它的容量是有限的,我们必须在其初始化的时候指定它的容量大小,容量大小一旦指定就不可改变。ArrayBlockingQueue是以先进先出的方式存储数据,最新插入的对象是尾部,最新移出的对象是头部

3.2.2 LinkedBlockingQueue

       LinkedBlockingQueue:阻塞队列大小的配置是可选的,如果我们初始化时指定一个大小,它就是有边界的,如果不指定,它就是无边界的。说是无边界,其实是采用了默认大小为Integer.MAX_VALUE的容量 。它的内部实现是一个链表。

代码04 BlockingQueue模拟生产与消费:src/com/mysoft/demo04/ProducerAndConsumer.java

package com.mysoft.demo04;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

class Producer extends Thread {

	private BlockingQueue<String> queue;
	private volatile boolean flag = true;
	private static AtomicInteger count = new AtomicInteger();

	public Producer(BlockingQueue<String> queue) {
		this.queue = queue;
	}

	@Override
	public void run() {
		try {
			System.out.println("生产者线程启动");
			while (flag) {
				System.out.println("生产者正在生产数据...");
				String data = count.incrementAndGet() + "";
				// 将数据存入队列
				boolean offer = queue.offer(data, 2, TimeUnit.SECONDS);
				if (offer) {
					System.out.println("生产者,存入" + data + "到队列中,成功!!!");
				} else {
					System.out.println("生产者,存入" + data + "到队列中,失败...");
				}
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.out.println("生产者退出线程");
		}
	}
	
	public void stopThread() {
		this.flag=false;
	}
}

class Consumer extends Thread{
	
	private BlockingQueue<String> queue;
	private volatile boolean flag=true;
	
	public Consumer(BlockingQueue<String> queue) {
		this.queue=queue;
	}
	
	@Override
	public void run() {
		try {
			System.out.println("消费者线程启动");
			while(flag) {
				System.out.println("消费者正在消费数据...");
				String data = queue.poll(2, TimeUnit.SECONDS);
				if(data!=null) {
					System.out.println("消费者,消费队列中的数据:" + data);
					Thread.sleep(1000);
				}else {
					System.out.println("消费者,超过2秒未获取到数据");
					flag=false;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			System.out.println("消费者退出线程...");
		}
	}
}

public class ProducerAndConsumer {

	public static void main(String[] args) throws InterruptedException {
		BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
		Producer p1=new Producer(queue);
		//Producer p2=new Producer(queue);
		Consumer c1=new Consumer(queue);
		p1.start();
		//p2.start();
		c1.start();
		
		// 执行10s
        Thread.sleep(10 * 1000);
        p1.stopThread();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值