JAVA并发包
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了JAVA并发包,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含9882字,纯文字阅读大概需要15分钟。
内容图文
![JAVA并发包](/upload/InfoBanner/zyjiaocheng/614/43475b9cb078492ebefd691748c2bd1c.jpg)
标题@java并发包
JAVA并发包
CopyOnWriteArrayList
多线程操作List集合,要保证线程安全,就使用CopyOnWriteArrayList
//定义线程类
public class MyThread extends Thread {
// public static List<Integer> list = new ArrayList<>();//线程不安全的
//改用:线程安全的List集合:
public static CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
list.add(i);
}
System.out.println("添加完毕!");
}
}
//测试类
public class Demo {
public static void main(String[] args) throws InterruptedException {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start();
t2.start();
Thread.sleep(1000);
System.out.println("最终集合的长度:" + MyThread.list.size());
}
}
//结果是正确的
CopyOnWriteArraySet
多线程操作set集合,保证线程安全,使用CopyOnWriteArraySet
//线程类
public class MyThread2 extends Thread {
// 共享集合
//static HashSet<Integer> set = new HashSet<>();// 线程不安全
static CopyOnWriteArraySet<Integer> set = new CopyOnWriteArraySet<>();// 线程安全
@Override
public void run() {
// 线程的任务:往集合中添加10000个元素
for (int i = 0; i < 10000; i++) {
set.add(i);
}
System.out.println("子线程执行完毕");
}
}
//测试类
public class Test2 {
public static void main(String[] args) throws InterruptedException {
// 需求: 多条线程操作同一个Set集合(往集合中添加10000个元素)
new MyThread2().start();
new MyThread2().start();
// 为了保证以上2条线程都操作完毕
Thread.sleep(2000);
System.out.println("集合元素个数:"+ MyThread2.set.size());// 10000个
}
}
ConcurrentHashMap
多线程操作Map集合,要保证线程安全,就使用ConcurrentHashMap集合
//线程类
public class MyThread3 extends Thread {
// 共享集合
static ConcurrentHashMap<Integer,Integer> map = new ConcurrentHashMap<>();// 线程安全
@Override
public void run() {
// 线程的任务:往集合中添加10000个键值对
for (int i = 0; i < 10000; i++) {
map.put(i,i);
}
System.out.println("子线程执行完毕");
}
}
//测试类
public class Test3 {
public static void main(String[] args) throws InterruptedException {
// 需求: 多条线程操作同一个Map集合(往集合中添加10000个键值对)
new MyThread3().start();
new MyThread3().start();
// 为了保证以上2条线程都操作完毕
Thread.sleep(2000);
System.out.println("集合元素个数:"+ MyThread3.map.size());// 10000
}
}
//HashTable效率低下原因
public synchronized V put(K key, V value)
public synchronized V get(Object key)
//HashTable容器使用synchronized来保证线程安全
// ConcurrentHashMap高效的原因
CountDownLatch
CountDownLatch允许一个或多个线程等待其他线程完成操作
//CountDownLatch构造方法:
public CountDownLatch(int count)// 初始化一个指定计数器的CountDownLatch对象 1
//CountDownLatch重要方法:
public void await() // 让当前线程等待
public void countDown() // 计数器进行减1
//1). 制作线程1:
public class MyRunnable1 implements Runnable {
CountDownLatch cdl;
public MyRunnable1(CountDownLatch cdl) {
this.cdl = cdl;
}
@Override
public void run() {
System.out.println("A");
// 暂停,等待线程2执行打印B,执行完回到这里来执行打印C
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("C");// 打印C之前一定要去执行打印B
}
}
//2). 制作线程2:
public class MyRunnable2 implements Runnable {
CountDownLatch cdl;
public MyRunnable2(CountDownLatch cdl) {
this.cdl = cdl;
}
@Override
public void run() {
System.out.println("B");
// 计数器-1
cdl.countDown();// 计数器的值为0
}
}
//3).制作测试类:
public class Test {
public static void main(String[] args) throws InterruptedException {
/*
CountDownLatch:
作用: 允许一个或多个线程等待其他线程完成操作。
常用方法:
public CountDownLatch(int count)// 初始化一个指定计数器的CountDownLatch对象
public void await() throws InterruptedException// 让当前线程等待
public void countDown() // 计数器进行减1
案例演示:
线程1的任务是打印A和C,线程2的任务是打印B,要求打印B一定要在打印C的前面
*/
CountDownLatch cdl = new CountDownLatch(1);
// 创建2条线程,执行任务
MyRunnable1 mr1 = new MyRunnable1(cdl);
Thread t1 = new Thread(mr1);
t1.start();
MyRunnable2 mr2 = new MyRunnable2(cdl);
Thread t2 = new Thread(mr2);
t2.start();//
}
}
//4). 执行结果:
会保证按:A B C的顺序打印。
//说明:
CountDownLatch中count down是倒数的意思,latch则是门闩的含义。整体含义可以理解为倒数的门栓,似乎有一点“三二一,芝麻开门”的感觉。
CountDownLatch是通过一个计数器来实现的,每当一个线程完成了自己的任务后,可以调用countDown()方法让计数器-1,当计数器到达0时,调用CountDownLatch。
await()方法的线程阻塞状态解除,继续执行。
CyclicBarrier
CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。
//CyclicBarrier构造方法
public CyclicBarrier(int parties, Runnable barrierAction)
//parties: 代表要达到屏障的线程数量
//barrierAction:表示达到屏障后要执行的任务
//CyclicBarrier重要方法:
public int await()// 每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞
//示例代码:
1). 制作员工线程:
public class MyRunnable implements Runnable {
CyclicBarrier cb;
public MyRunnable(CyclicBarrier cb) {
this.cb = cb;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":到会议室了...");
// 当前线程到达会议室(屏障),暂停
try {
cb.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":离开会议室");
}
}
2). 制作开会线程:
public class MeetingRunnable implements Runnable {
@Override
public void run() {
System.out.println("会议开始,会议的内容是...");
}
}
3). 制作测试类:
public class Test {
public static void main(String[] args) {
/*
CyclicBarrier类:
作用:它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,
所有被屏障拦截的线程才会继续运行。
常用方法:
public CyclicBarrier(int parties, Runnable barrierAction)
parties: 代表要达到屏障的线程数量
barrierAction:表示达到屏障后要执行的线程
public int await() 每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞
案例演示:
例如:公司召集5名员工开会,等5名员工都到了,会议开始
*/
// 创建CyclicBarrier对象
CyclicBarrier cb = new CyclicBarrier(5,new MeetingRunnable());
MyRunnable mr = new MyRunnable(cb);
new Thread(mr,"员工1").start();
new Thread(mr,"员工2").start();
new Thread(mr,"员工3").start();
new Thread(mr,"员工4").start();
new Thread(mr,"员工5").start();
}
}
4). 执行结果:
//使用场景
使用场景:CyclicBarrier可以用于多线程计算数据,最后合并计算结果的场景。
需求:使用两个线程读取2个文件中的数据,当两个文件中的数据都读取完毕以后,进行数据的汇总操作。
Semaphore
Semaphore的主要作用是控制线程的并发数量。
synchronized可以起到"锁"的作用,但某个时间段内,只能有一个线程允许执行。
Semaphore可以设置同时允许几个线程执行。
Semaphore字面意思是信号量的意思,它的作用是控制访问特定资源的线程数目。
//Semaphore构造方法:
public Semaphore(int permits) permits 表示许可线程的数量
//Semaphore重要方法:
public void acquire() 表示获取许可
public void release() 表示释放许可
//- 示例一:同时允许1个线程执行
1). 制作一个ClassRoom类:
public class ClassRoom {
Semaphore sp;
public ClassRoom(Semaphore sp) {
this.sp = sp;
}
public void into(){
// 获得许可
try {
sp.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":获得许可,进入了教室...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":释放许可,离开教室");
// 释放许可
sp.release();
}
}
//2). 测试类:
public class Test {
public static void main(String[] args) {
// 需求:多线程模拟5个人进入教室,但教室只允许3个人在里面
// 创建教室对象
Semaphore sp = new Semaphore(2);
ClassRoom cr = new ClassRoom(sp);
new Thread(new Runnable() {
@Override
public void run() {
cr.into();
}
}, "同学1").start();
new Thread(new Runnable() {
@Override
public void run() {
cr.into();
}
}, "同学2").start();
new Thread(new Runnable() {
@Override
public void run() {
cr.into();
}
}, "同学3").start();
new Thread(new Runnable() {
@Override
public void run() {
cr.into();
}
}, "同学4").start();
new Thread(new Runnable() {
@Override
public void run() {
cr.into();
}
}, "同学5").start();
}
}
Exchanger
Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。
这两个线程通过exchange方法交换数据,如果第一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。
A线程 exchange方法 把数据传递B线程
B线程 exchange方法 把数据传递A线程
//Exchanger构造方法:
public Exchanger()
//Exchanger重要方法:
public V exchange(V x) 交换数据,参数是要传递给其他线程的数据,返回值是其他线程传递过来的数据
//示例一
public class MyRunnable1 implements Runnable {
Exchanger<String> ex;
public MyRunnable1(Exchanger<String> ex) {
this.ex = ex;
}
@Override
public void run() {
// 线程1 传递数据给 线程2
try {
// 线程1,把"信息1"传递给线程2
String message2 = ex.exchange("信息1");
System.out.println("线程2 传递给 线程1的信息是:"+message2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class MyRunnable2 implements Runnable {
Exchanger<String> ex;
public MyRunnable2(Exchanger<String> ex) {
this.ex = ex;
}
@Override
public void run() {
// 线程2 传递数据给 线程1
try {
String message1 = ex.exchange("信息2");
System.out.println("线程1 传递给 线程2的信息:"+message1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//2). 制作main()方法:
public class Test {
public static void main(String[] args) {
/*
Exchanger类:
作用:是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。
常用方法:
public Exchanger()
public V exchange(V x) 参数就表示当前线程需要传递的数据,返回值是其他线程传递过来的数据
案例演示:
*/
Exchanger<String> ex = new Exchanger<>();
MyRunnable1 mr1 = new MyRunnable1(ex);
new Thread(mr1).start();
MyRunnable2 mr2 = new MyRunnable2(ex);
new Thread(mr2).start();
}
}
//使用场景:可以做数据校对工作
需求:比如我们需要将纸制银行流水通过人工的方式录入成电子银行流水。为了避免错误,采用AB岗两人进行录入,录入到两个文件中,系统需要加载这两个文件,
并对两个文件数据进行校对,看看是否录入一致,
内容总结
以上是互联网集市为您收集整理的JAVA并发包全部内容,希望文章能够帮你解决JAVA并发包所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。