java并发(二):深入分析volatile实现原理
volatile的原理实现可以看这篇文章,真的是从硬件层面上说明了volatile怎样保证可见性
下面这个实例,如果没有设置成volatile关键字,那么线程读的 isRunning永远都是自己私有内存中的,线程将会一直在while循环中
public class RunThread extends Thread{ private volatile boolean isRunning = true; private void setRunning(boolean isRunning){ this.isRunning = isRunning; } public void run(){ System.out.println("进入run方法.."); int i = 0; while(isRunning == true){ //.. } System.out.println("线程停止"); } public static void main(String[] args) throws InterruptedException { RunThread rt = new RunThread(); rt.start(); Thread.sleep(1000); rt.setRunning(false); System.out.println("isRunning的值已经被设置了false"); } }
这是展示volatile虽然有可见性,但是没有原子性:
/** * volatile关键字不具备synchronized关键字的原子性(同步) * @author alienware * */ public class VolatileNoAtomic extends Thread{ private static volatile int count = 0; //这个被注释的代码可以保证结果正确 //private static AtomicInteger count = new AtomicInteger(0); private static void addCount(){ for (int i = 0; i < 1000; i++) { count++ ; //这个被注释的代码可以保证结果正确 //count.incrementAndGet(); } System.out.println(count); } public void run(){ addCount(); } public static void main(String[] args) { VolatileNoAtomic[] arr = new VolatileNoAtomic[100]; for (int i = 0; i < 10; i++) { arr[i] = new VolatileNoAtomic(); } for (int i = 0; i < 10; i++) { arr[i].start(); } } }
这是使用atomic,保证原子性的代码:
public class AtomicUse { private static AtomicInteger count = new AtomicInteger(0); //多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性 /**synchronized*/ public synchronized int multiAdd(){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } count.addAndGet(1); count.addAndGet(2); count.addAndGet(3); count.addAndGet(4); //+10 return count.get(); } public static void main(String[] args) { final AtomicUse au = new AtomicUse(); List<Thread> ts = new ArrayList<Thread>(); for (int i = 0; i < 100; i++) { ts.add(new Thread(new Runnable() { @Override public void run() { System.out.println(au.multiAdd()); } })); } for(Thread t : ts){ t.start(); } } }
线程通信
ListAdd2.java,可以看出本来list已经到5了,那么t2应该出while循环抛异常,但是因为它执行了wait方法,释放锁了。而t1得到锁一直执行,虽然t1执行了notify方法,但是只是发出通知而已,只有它的方法执行完才释放锁让t2执行。
package com.bjsxt.base.conn008; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingQueue; /** * wait notfiy 方法,wait释放锁,notfiy不释放锁 * @author alienware * */ public class ListAdd2 { private volatile static List list = new ArrayList(); public void add(){ list.add("bjsxt"); } public int size(){ return list.size(); } public static void main(String[] args) { final ListAdd2 list2 = new ListAdd2(); // 1 实例化出来一个 lock // 当使用wait 和 notify 的时候 , 一定要配合着synchronized关键字去使用 final Object lock = new Object(); // final CountDownLatch countDownLatch = new CountDownLatch(1); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { 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("已经发出通知.."); // countDownLatch.countDown(); lock.notify(); } } } } 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(); // countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止.."); throw new RuntimeException(); } } }, "t2"); t2.start(); t1.start(); } }
package com.xushu.multi; import java.util.LinkedList; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class MyQueue { private LinkedList<Object> list = new LinkedList<Object>(); private AtomicInteger count = new AtomicInteger(0); private final int minSize = 0; private final int maxSize; public MyQueue(int size) { this.maxSize = size; } private final Object lock = new Object(); public void put(Object obj) { synchronized (lock) { if (count.get() == this.maxSize) { try { lock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } list.add(obj); count.incrementAndGet(); lock.notify(); System.out.println("新加入的元素为:" + obj); } } public Object take() { Object ret = null; synchronized (lock) { if (count.get() == minSize) { try { lock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } ret = list.removeFirst(); count.decrementAndGet(); lock.notify(); } return ret; } public int getSize() { return this.count.get(); } public static void main(String[] args) { final MyQueue mq = new MyQueue(5); mq.put("a"); mq.put("b"); mq.put("c"); mq.put("d"); System.out.println("当前容器的长度:" + mq.getSize()); Thread t1 = new Thread(new Runnable() { @Override public void run() { mq.put("f"); mq.put("g"); mq.put("e"); } }, "t1"); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { Object o1 = mq.take(); System.out.println("移除的元素为:" + o1); Object o2 = mq.take(); System.out.println("移除的元素为:" + o2); } }, "t2"); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } t2.start(); } }
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Java8及新版本许可证及收费?
问题:许可类型及如何收费? JDK 8 Oracle 将继续提供JDK 8 免费的公共更新和自动更新,支持个人用户到 2020 年 12 月底,支持商业用户到 2019 年 1 月;换句话说如果想 Oracle 后续继续为你提供 JDK 8 的支持,那么则需要付费。Oracle目前只提供了部分平台的JDK 8的openJDK构建,多数平台只有第三方的openjdk可以用。 按照 Oracle 公布的支持路线图: java支持路线图 如上图绿色的部分为免费支持的openJDK版本。棕红色部分为Oracke JDK Java SE Advanced, 该系列的产品是收费的,只有在「通用计算」使用范围内是完全免费的。显然通用计算不包括商业使用。 对于最新的java 11 Oracle JDK:支持 BCL 协议,开发人员可以免费使用,但不能用于生产,生产需要商业许可,如果全额付费的话,可支持到 2026 年 9 月。 OpenJDK:支持 GPL V2+CPE协议「一般只支持到发布以后的 6 个月」,可以用于公司使用,因此,对于JDK 11 来说,应该有JDK 11.0.0,然后是两个安全补...
- 下一篇
区块链教程Fabric1.0源代码分析Chaincode(链码)体系总结-兄弟连
Fabric 1.0源代码笔记 之 Chaincode(链码) 1、Chaincode概述 Chaincode,即链码或智能合约,代码分布在protos/peer目录、core/chaincode和core/common/ccprovider目录,目录结构如下: protos/peer目录:* chaincode.pb.go,ChaincodeDeploymentSpec、ChaincodeInvocationSpec结构体定义。 core/chaincode目录:* platforms目录,链码的编写语言平台实现,如golang或java。 * platforms.go,Platform接口定义,及部分工具函数。* java目录,java语言平台实现。* golang目录,golang语言平台实现。 core/common/ccprovider目录:ccprovider相关实现。 2、protos相关结构体定义 2.1、ChaincodeDeploymentSpec结构体定义(用于Chaincode部署) 2.1.1 ChaincodeDeploymentSpec结构体定义 type...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8编译安装MySQL8.0.19
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2整合Redis,开启缓存,提高访问速度