线程相关—锁
来源:互联网 发布:天互数据备案 编辑:程序博客网 时间:2024/06/16 13:55
1.闭锁CountDownLatch
闭锁:想实现它管理的线程都执行完后,在执行其它线程。
在调用构造方法创建CountDownLatch对象时需要指定管理线程的个数(计数器的值)。
await():会产生阻塞,直到计数器减为0的时候才会释放。
countDown():每调用一次,会将计数器–。
例子:锅和菜买回来之后,才可以输出开始做饭
//两个线程类class BuyGuo implements Runnable{ private CountDownLatch cdl ; public BuyGuo(CountDownLatch cdl){ this.cdl = cdl; } public void run(){ System.out.println("锅买回来了..."); cdl.countDown(); }}class BuyCai implements Runnable{ private CountDownLatch cdl; public BuyCai(CountDownLatch cdl){ this.cdl = cdl; } public void run(){ System.out.println("菜买回来了..."); cdl.countDown(); }}//主方法public static void main(String[] args) { //创建闭锁,管理2个线程 CountDownLatch cdl = new CountDownLatch(2); //将闭锁传入。 new Thread(new BuyGuo(cdl)).start(); new Thread(new BuyCai(cdl)).start(); try { //阻塞,直到上述2个线程执行完毕再继续执行。 cdl.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("开始做饭..."); }
2.栅栏 CyclicBarrier
也需要在创建时确定管理线程个数,await()方法是加法了,产生阻塞并且计数器加一,当加到管理线程的个数时,释放阻塞。
public class DemoCyclicBarrier { public static void main(String[] args) { CyclicBarrier cb = new CyclicBarrier(2); new Thread(new Horse1(cb)).start(); new Thread(new Horse2(cb)).start(); }}class Horse1 implements Runnable{ private CyclicBarrier cb; public Horse1(CyclicBarrier cb){ this.cb = cb; } public void run(){ System.out.println("第一匹马来到起跑线,做好了准备.."); try { //阻塞,知道计数器为2时才释放。 cb.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println("第一匹马开始比赛...跑起"); }}class Horse2 implements Runnable{ private CyclicBarrier cb; public Horse2(CyclicBarrier cb){ this.cb = cb; } public void run(){ System.out.println("第二匹马正在拉肚子ing...."); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("第二匹马来到了起跑线,准备好..."); try { //阻塞,知道计数器为2时才释放。 cb.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println("第二匹马开始比赛...跑起"); }}//两匹马同时起跑~~
CountDownLatch和CyclicBarrier的主要联系和区别如下:(这段转自千山独行大大的博客~)
1.闭锁CountDownLatch做减计数,而栅栏CyclicBarrier则是加计数。
2.CountDownLatch是一次性的,CyclicBarrier可以重用。
3.CountDownLatch强调一个线程等多个线程完成某件事情。CyclicBarrier是多个线程互等,等大家都完成。
4.鉴于上面的描述,CyclicBarrier在一些场景中可以替代CountDownLatch实现类似的功能。
3.交换机 Exchanger
public class DemoExchanger { public static void main(String[] args) { //创建交换机。 Exchanger<String> exc = new Exchanger<String>(); new Thread(new Spy1(exc)).start(); new Thread(new Spy2(exc)).start(); }}class Spy1 implements Runnable{ private Exchanger<String> exc; public Spy1(Exchanger<String> exc){ this.exc = exc; } public void run(){ //返回的是线程2传给线程1的内容 try { //该方法给线程传信息,并接收对方传的信息。 String msg = exc.exchange("天王盖地虎"); System.out.println("间谍2传给间谍1的信息:"+msg); } catch (InterruptedException e) { e.printStackTrace(); } }}class Spy2 implements Runnable{ private Exchanger<String> exc; public Spy2(Exchanger<String> exc){ this.exc = exc; } public void run(){ //返回的是线程2传给线程1的内容 try { //该方法给线程传信息,并接收对方传的信息。 String msg = exc.exchange("宝塔镇河妖"); System.out.println("间谍1传给间谍2的信息:"+msg); } catch (InterruptedException e) { e.printStackTrace(); } }}
4.锁—lock
之前线程安全问题需要解决,都会用synchronized同步代码块,这个方法我们还需要指定锁的钥匙,不够灵活。
synchronized:
假设切换线程时,线程1运行一次,然后等待,唤醒线程2,线程2运行。这期前假设运行时间1s,唤醒时间2秒。那么运行2次的时间一共是4秒。
lock:lock在唤醒期间,如果线程2没醒会多次运行,线程1运行1秒后,线程2处再唤醒中,那么线程1会在唤醒的2秒中继续运行2次,等线程2唤醒后,线程2运行。那么4秒的时间一共运行了4次。
lock代码具体如下:
public class TestDemo3 { public static String name="李雷"; public static String gender = "男"; public static void main(String[] args) { Lock lock = new ReentrantLock(); new Thread(new ReadRunner3(lock)).start(); new Thread(new WriteRunner3(lock)).start(); }}class ReadRunner3 implements Runnable{ private Lock lock; public ReadRunner3(Lock lock){ this.lock = lock; } public void run(){ while(true){ //添加锁 lock.lock(); System.out.println(TestDemo3.name+","+TestDemo3.gender); //释放锁,如果涉及到异常处理的代码,该行代码一定要放在finally中 lock.unlock(); } }}class WriteRunner3 implements Runnable{ private Lock lock; public WriteRunner3(Lock lock){ this.lock= lock; } public void run(){ while(true){ lock.lock(); if("李雷".equals(TestDemo3.name)){ TestDemo3.name = "韩梅梅"; TestDemo3.gender ="女"; }else{ TestDemo3.name="李雷"; TestDemo3.gender="男"; } lock.unlock(); } }}
读写锁ReadWriteLock
读写锁分为读锁和写锁,与Lock的区别就是,读锁和读锁之间可以共存,如果是对一条数据的多个请求的读操作,不会进行锁定,但是读锁和写锁,写锁和写锁会被锁定。
代码升级:
public class TestDemo4 { public static String name="李雷"; public static String gender = "男"; public static void main(String[] args) { ReadWriteLock lock = new ReentrantReadWriteLock (); new Thread(new ReadRunner4(lock)).start(); new Thread(new WriteRunner4(lock)).start(); }}class ReadRunner4 implements Runnable{ private ReadWriteLock lock; public ReadRunner4(ReadWriteLock lock){ this.lock = lock; } public void run(){ while(true){ //添加锁 lock.readLock().lock(); System.out.println(TestDemo4.name+","+TestDemo4.gender); //释放锁,如果涉及到异常处理的代码,该行代码一定要放在finally中 lock.readLock().unlock(); } }}class WriteRunner4 implements Runnable{ private ReadWriteLock lock; public WriteRunner4(ReadWriteLock lock){ this.lock= lock; } public void run(){ while(true){ lock.writeLock().lock(); if("李雷".equals(TestDemo4.name)){ TestDemo4.name = "韩梅梅"; TestDemo4.gender ="女"; }else{ TestDemo4.name="李雷"; TestDemo4.gender="男"; } lock.writeLock().unlock(); } }}
5.原子性AtomicInteger
如果设置一个静态成员变量,2个线程分别从1加到100000,那么结束后输出最后的结果,会是多少呢?
会是200000嘛?不会,因为线程安全没有任何措施,导致会有重复的相加,即两个线程同时加完后结果只加了1.而不是加2.
添加synchronized同步代码块或锁可以解决该问题,我们还有别的解决方案,原子性AtomicInteger
public class DemoAtomic { //新建原子性变量。 public static AtomicInteger num = new AtomicInteger(0); public static void main(String[] args) { //闭锁,全部完成后再输出结果 CountDownLatch cdl = new CountDownLatch(2); new Thread(new AddRunner(cdl)).start(); new Thread(new AddRunner(cdl)).start(); try { cdl.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(num); }}class AddRunner implements Runnable{ private CountDownLatch cdl; public AddRunner(CountDownLatch cdl){ this.cdl = cdl; } public void run(){ for (int i = 0; i < 100000; i++) { //每次加一 相当于num++ DemoAtomic.num.getAndAdd(1); } cdl.countDown(); }}
其源码的逻辑是每次加完后会进行安全检查,如果发现重复相加则再加一次,直至没有重复相加。
- 线程相关—锁
- 关于线程锁的相关
- 性能监控/优化系列——内存/线程/锁相关
- 线程相关
- 线程相关
- 线程相关
- 线程相关
- 线程相关
- 线程相关。
- 线程相关
- 线程相关
- 线程相关
- 线程相关
- 线程相关
- 线程相关
- 线程相关
- 线程相关
- 线程同步,锁的相关问题
- Python合并Excel表格(自动合并)
- 分析并写出下列程序的运行结果
- mybatis绑定错误-- Invalid bound statement (not found)
- 【水题】HDU 2043 密码
- 自定义服务_显示当前时间
- 线程相关—锁
- TCP/IP网络协议
- 5.8
- 数据库sql给某列添加唯一约束
- 杭电ACM 1062: Text Reverse
- centos7 sudo命令详解
- Java数组无法动态分配数组长度
- Android5.1系统如何通过包名给应用开放系统权限
- CentOS7.x上怎么安装iptables