首页 文章 精选 留言 我的

精选列表

搜索[集合],共10003篇文章
优秀的个人博客,低调大师

Java之Set集合的"怪"

工作中可能用Set比较少,但是如果用的时候,出的一些问题很让人摸不着头脑,然后我就看了一下Set的底层实现,大吃一惊。 看一个问题 Map map = new HashMap(); map.put(1,"a"); map.put(12,"ab"); map.put(123,"abc"); Set set1 = map.keySet(); Set set2 = map.keySet(); Set set3 = map.keySet(); set1.remove(1); set1.forEach(p-> System.out.println(p.toString())); set2.forEach(p-> System.out.println(p.toString())); set3.forEach(p-> System.out.println(p.toString())); 然后我的运行结果是 123 12 ---------------- 123 12 ---------------- 123 12 为什么我在set1里面执行remove(1);其它的两个set对象为什么也删掉了第一个元素呢? 为什么会受到我前面操作的影响呢。 分析底层实现 1.最简单的实践 我们大概能猜出问题的所在,就是set1其实调用的还是map对象。那怎样才具有说服力呢。 学过反射的应该都清楚,我们可以看下set1它到底是什么类型的对象。 Class classes = set1.getClass(); System.out.println(classes.getTypeName()); 控制台打印: java.util.HashMap$KeySet 是不是眼前一亮,wtf竟然是个Map类型。我不是明明给它实例化了个Set对象吗。好了,这个现象成功吸引了我的兴趣。于是 找底层实现 我们找到这个KeySet方法 public Set<K> keySet() { Set<K> ks = keySet; if (ks == null) { ks = new AbstractSet<K>() { public Iterator<K> iterator() { return new Iterator<K>() { private Iterator<Entry<K,V>> i = entrySet().iterator(); public boolean hasNext() { return i.hasNext(); } public K next() { return i.next().getKey(); } public void remove() { i.remove(); } }; } public int size() { return AbstractMap.this.size(); } public boolean isEmpty() { return AbstractMap.this.isEmpty(); } public void clear() { AbstractMap.this.clear(); } public boolean contains(Object k) { return AbstractMap.this.containsKey(k); } }; keySet = ks; } return ks; } 我们可以看到,有一个成员内部类AbstractSet<K>(),里面有两部分,一部分是new 一个迭代器(内部类),一部分是调用AbstractMap对象(外部类)。外部类对象调用的内部类的构造函数,反编译的话,会看出传入了外部类对象的引用进去。所以它最终的类型应该是AbstractMap,(Map的派生类)。 所以,眼看是实例化了一个Set对象,其实底层还是调用的map对象。

优秀的个人博客,低调大师

React Native 常见问题集合

在使用React Native时候,我记录下比较常遇到的问题,分为以下几类: 1. 调试问题 2. 写法问题 3. 疑难问题 4. 奇怪问题 调试问题 1. 在react-native run-android运行后,真机上打开的空白页面。 我测试机是红米2A(Android 4.4.4),在调试时,发现没有reload的菜单栏,也没有日志出现。 原因:需要到应用->权限管理->显示悬浮窗打开,这样才可以查看错误日志。 2. 打成的apk安装包安装后, 替换的图片(应用icon)没有变,还是旧图片? 原因:这应该是你机器本来就安装过测试包了,有了缓存,重启下机器就可以了。 3. 怎么进行js调试? 解答:可以在代码里面写一个debugger,然后在手机上点击"start remote js debugging",这是会自动打开一个Chrome页面,打开开发者控制台。当代码经过debugger时候,即可调试。 写法问题 1. Application simpleAPP has not been registered. This is either due to a require() error during initialization or failure to call AppRegistry.registerComponent. 原因:AppRegistry.registerComponent('testProject', () => RnListView); 这一句,要看testProject这个参数有没有写对,是不是跟应用名一样(你初始化的应用名)。 2. Adjacent JSX elements must be wrapped in an enclosing tag. 例如: render: function() { return ( <h1>something</h1> <div> something else </div> ); } }); 原因:React element can return only one element. 官方有Q&A说明,只能返回一个element,上面返回了两个element。 3.图片加载不了? 例1: var localImg = "./images/demo/newsImg2.png"; require( localImg ); 例2: require( "./images/demo/newsImg2.png"); 第一种情况加载不了。 原因:为了使新的图片资源机制正常工作,require中的图片名字必须是一个静态字符串,这是React规定。 4. 为什么要这样写onPress={ () => this.goback() } ,而不是onPress={ this.goback } ? 原因:我认为是为了保持goback函数里this的指向。 疑难问题 1. Android状态栏的“沉浸式”设置无效? 例如: <StatusBar backgroundColor='blue' translucent = {true} /> 经过我的尝试,hidden属性是有效,但translucent的效果没有出现。 不过有另外解决方法: 在styles.xml加上: <style name="ImageTranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowTranslucentStatus">true</item> <item name="android:windowTranslucentNavigation">true</item> </style> 在manifest的activity加上: android:theme="@style/ImageTranslucentTheme" 然后在每个页面的Header都要相应加多高度来适应: paddingTop: 20, height: 68, 2.react-native-gifted-listview用这个组件时候,报了两个warning! (1). In next release empty section headers will be rendered. In this release you can user 'enableEmptySections' flag to render empty section headers. 解决:找到node_modules下的react-native-gifted-listview,在ListView下 加个enableEmptySections={true} 就可以解决了。 (2). Circular indeterminate 'ProgressBarAndroid' is deprecated. Use 'ActivityIndicator' instead. 解决:找到node_modules下的react-native-gifted-spinner,修改组件。 PS:这个组件开发者没有及时更新。 3.TouchableHighlight的onPress事件无效,总报“undefined is not a function”? 例如: _pressRow(title){ Alert.alert( 'Alert Title', "fuck",[{ text: 'OK', onPress: () => console.log('OK Pressed!')}]) } _renderRowView(rowData) { return ( <TouchableHighlight underlayColor='#c8c7cc' onPress={ () => this._pressRow(rowData.title)}> </TouchableHighlight> ); } render() { return ( <ScrollView> <ListView dataSource={this.state.dataSource} renderRow={ this._renderRowView}/> </ScrollView> ); } 原因:renderRow={ this._renderRowView},里面渲染的列里面的this不再是最外层的this,需要改成this._renderRowView.bind(this)。 4.尺寸怎么计算,设计图到具体数值? 解决:这个可以查看https://segmentfault.com/a/1190000002658374这篇文章,挺详细的。 5.组件之间的传值怎么做? 解决:这个可以查看http://blog.csdn.net/gz_jero/article/details/51531247。 6. 怎么图片显示不完整? 代码如下(只显示部分): // Card视图 var Card = React.createClass({ showToast: function(num: i) { ToastAndroid.show(NAMES[num].toString(), ToastAndroid.SHORT); }, // 左右留空, 中间匹配 render: function() { return ( <TouchableOpacity style={styles.button} onPress={() => this.showToast(this.props.num)} > <Image style={styles.image} resizeMode={'cover'} source={this.props.img}/> </TouchableOpacity> ); } }); // 批量创建 var createCardRow = (img, i) => <Card key={i} img={img} num={i}/>; var ListViewModule = React.createClass({ render: function() { var verticalScrollView = ( <ScrollView style={styles.container}> {IMAGES.map(createCardRow)} </ScrollView> ); return verticalScrollView; } }); var styles = StyleSheet.create({ container: { flex: 1, }, button: { justifyContent: 'space-between', alignItems: 'center', flexDirection: 'row', margin: 10, }, image: { flex: 1, height: 200, borderRadius: 5, borderWidth: 2, borderColor: '#FF1492', }, blank: { width: 10, } }); 原因:当图片没有设置width具体数值,弹性布局并不会将图片自适应到整个容器宽度,而是按着图片本身大小显示。 简单说就是图片不能用flex设置宽度。(这个原因是我的猜想) 我在Web做了测试: <div style="width:200px;flex:'flexDirection';"> <img src="F:\workspace_react\testProject\list_view_module\images\jessicajung.png" style="flex:1"/> <div style="flex:1">234</div> </div> 实验结果是,上面图片宽度还是732px,而下面的div是200px。 奇怪问题 1. 页面变得可以左右拖动,可以看到一片空白。 原因:当Navigator组件设置的转场动画是Navigator.SceneConfigs.HorizontalSwipeJump,那就会导致一个神奇的效果,页面可以左右拖动,看到一片空白区域(这个效果我觉得慎用)。 2.Github上有时有些库按命令装不了。 在安装库时候,发现了奇怪的现象。有时安装时,安装会报错。 解决:尝试加上--save或者删除--save就可以了! 3. 为什么要从react-native、react两个不同地方important组件? 例如: import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, View } from 'react-native'; react-native应该是包含原生组件部分,而React应该是与平台无关的基础组件。 本文为原创文章,转载请保留原出处,方便溯源,如有错误地方,谢谢指正。 本文地址 : http://www.cnblogs.com/lovesong/p/5679340.html 本文转自 海角在眼前 博客园博客,原文链接: http://www.cnblogs.com/lovesong/p/5679340.html ,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android学习笔记系列教程集合

Android学习笔记系列 Android应用开发笔记(1):调用打电话和发短信、收短信接口、发Email (Call, Dial, SMSManager, Broadcast, Email) Android应用开发笔记(2):读取手机中的联系人信息(android.provider.ContactsContract) Android应用开发笔记(3):SQLite数据库的插入删除查询操作 Android应用开发笔记(4):再探Android多应用间数据共享机制,自定义ContentProvider Android应用开发笔记(5):Android中的Service使用 Android应用开发笔记(6):Toast、Notification、Alarm, Android中的通知实现 Android应用开发笔记(7):构建自己的Android账户与内容同步机制,例程SampleSyncAdapter的分析 Android应用开发笔记(8):在背景运行耗时任务,AsyncTask与ProgressDialog的使用 Android应用开发笔记(9):应用中调用系统的搜索UI,Android Search Framework的初步了解 Android应用开发笔记(10):制作自定义背景Button按钮、自定义形状Button的全攻略 Android应用开发笔记(11):Android上的蓝牙通信功能的开发:BluetoothChat例程分析 Android应用开发笔记(12):Android应用的自动升级、更新模块的实现 Android应用开发笔记(13): Android移动应用界面的模板化设计 这个教程真的很值得收藏!!每一篇都写得很好。 分类: Android开发 本文转自qianqianlianmeng博客园博客,原文链接:http://www.cnblogs.com/aimeng/archive/2012/01/06/2314394.html ,如需转载请自行联系原作者

优秀的个人博客,低调大师

Azure操作手册集合

《Windows Azure Platform 系列文章目录》 第一篇: Azure EA Portal管理手册,主要面向Azure企业管理员,介绍 - 如何将测试订阅转为生产订阅 - 如何创建新部门 - 如何创建新账户 - 如何创建新订阅 - 如何设置协同管理员 - 如何查看账单 - 如何设置邮件通知 最后更新时间为2017年11月13日 EA Portal管理手册 第二篇: Azure IaaS用户手册(最新更新2016年6月6日) - Azure IaaS相关技术 - Azure虚拟机成本分析 - 创建Azure虚拟机 - 使用Azure PowerShell创建Azure虚拟机 - 管理Azure虚拟机 - 高级内容 - 注意事项 IaaS用户手册 第三篇: Azure Web Apps用户手册(最新更新2016年9月21日) - Azure Web Apps架构 - Azure Web Apps服务类型 - Azure Web Apps成本分析 - Azure Web Apps限制 - 将网站代码通过FTP部署 - 高级内容 Web Apps用户手册 第四篇: Azure Storage用户手册(最新更新2016年1月8日) Storage Apps用户手册 第五篇 Azure SQL Database用户手册(最新更新2016年6月17日) Azure SQL Database用户手册 第六篇 Azure Cloud Service用户手册(最新更新2016年6月14日) Cloud Service用户手册 本文转自Lei Zhang博客园博客,原文链接:http://www.cnblogs.com/threestone/p/4627388.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

真假云主机,VPS资料集合

资料来源: http://www.west263.com/services/CloudHost/pk.asp?ads=baidu912 用"云里雾里"形容中小企业用户对云计算的理解与认知并不为过,毕竟云计算这一概念并没有统一标准,而云主机作为云计算构建的基石和最早落地的先遣产品,自然而然地成为一些中小IDC"山寨"的目标,让大街小巷到处充斥着"云"的身影。 低廉的价格,无处不在的云概念,仿佛云计算早已在中国普及。打开百度、淘宝一搜,会发现有数百家大大小小的公司、甚至个人都可 以提供"云主机","云主机"基本上已经成为所有IDC必备的产品线,以往卖域名、虚拟主机、VPS的,现在基本上都开始卖"云主机"了,毕竟云主机现在 确实很火,亚马逊、阿里、腾讯、盛大等巨头都纷纷涉足云计算行业。但云主机真的这么简单,个人也能提供云主机么? "其实,很多用户正在使用的“云主机”并非真正的云主机,而只是被部分服务商换了名字的VPS!VPS是通过虚拟化软件让一台服务器虚拟出多台主机,部分IDC直接拿VPS当云主机来卖。"业内人士一针见血地指出目前云主机市场的问题所在。 到底什么才是真正的云主机?什么是VPS?我们先来看看云主机和VPS的定义: 云主机:云主机是整合了计算、存储与网络资源的IT基础设施能力租用服务,能提供基于云计算模式的按需使用和按需付费能力的服务器租用服务。云主机是在由若干台服务器组成的集群上虚拟出多个类似独立主机的部分,它具备可靠性高、灵活性强等特点。详见百度百科:http://baike.baidu.com/view/2482016.htm VPS:Virtual Private Server (虚拟专用服务器)是利用虚拟服务器软件(如微软的Hyper-v、VMware、SWsoft 的Virtuozzo)在一台物理服务器上创建多个相互隔离的小服务器。这些小服务器(VPS)本身就有自己操作系统,它的运行和管理与独立服务器完全相 同。 对于终端用户,特别是只需要一两台服务器的小用户来说,拿到手的云主机或VPS通过远程桌面登录后,管理功能是类似的,都能看到服务商所标称的几个 CPU、多少内存、多大硬盘等参数,所以在使用感知上云主机和VPS并不明显。正是因为这方面的原因,也给了很多小的IDC服务商以可乘之机,能堂而皇之 地把VPS慌称为"云主机"且在很多时候还能蒙混过关。其实VPS主机有的确有一些它的优势,比如成本低,用户能以极低的价格就能获得类似独立主机一样的功能,在最近几年有着不少的用户选择VPS主机。所以卖VPS主机是没问题的,毕竟有很多对可靠性要求不是特别高的用户确实需要这样的产品,但为了利润与噱头,就把VPS主机当云主机来卖就有点不厚道了。毕竟VPS与云主机的成本和可靠性不在同一个层次。 云主机比起VPS到底有何优势?有没有简单的办法可以辨别云主机的真伪呢? 从上文的介绍可以看出,VPS是一台服务器在为多个VPS用户提供服务,这些VPS子服务器的带宽、硬盘IO性能、CPU能力等等都受制于这台"母服 务器"的性能,如果母服务器的硬盘损坏、主板损坏等,则意味着上面的所有VPS服务器都将宕机,需要相当长的时间才能恢复服务。而云主机是若干台服务器组 成的集群在同时提供服务,集群中的一两台服务器的宕机并不影响云主机的正常使用,云主机的磁盘IO性能、带宽、内存等都不受制于单台服务器的限制,可以灵 活方便地自由扩展。 简单地说就是一台服务器在为多个VM服务的就是假云,多个服务器同时为一个VM服务的才是真云! 下面通过一些对比来简要说明真正的云主机和假云的区别: 真云主机 假云或VPS 简要说明 一、看云主机存储模式 网络分布式集群存储,数据实时写多份 采用单机本地硬盘存储(也就是一台物理机),数据只写一份 数据的存储方式是真云与假云的本质区别,为数据提供超高可靠性是云计算技术出现并风靡于全球的 根本原因之一,只有基于网络,才能将数据写入多分,实现分散存储,才能为规避单点故障与动态迁移打下基础,而假云只是普通的VPS,数据保存于本地硬盘, 鸡蛋只在一个篮子,机器故障与数据丢失的风险将一直存在,用户只能祈求此机器足够可靠与稳定了。 假云服务商一般只罗列产品型号和价格,没有更多关于底层架构、存储方式等介绍,而真正的云主机提供商会提供详细的架构说明、存储方式、优势对比等,比如阿 里云基于其自行开发的飞天平台,西部数码弹性云是在开源的KVM+Hadoop基础上整合开发。 二、看可靠性如何保障 多台物理服务器支撑, 支持热迁移和异节点快速重建 如果母服务器主板或硬盘故障等,可能导致数小时甚至更长的中断时间 一个机房的数千台服务器中,每一台机器都有死机或故障的可能。在原计算节点需要升级配置或部分配件性能降低需要关机维护时,可以通过热迁移功能将上面的云 主机瞬间迁移至其他节点,云主机上的业务不会中断,不需要重启。而VPS在遇到上述情况时,通常需要停机操作,中断较长的时间。 在计算节点机器发生突发硬件故障时,真正的云主机支持自动重建到其他节点,仅需要5~10分钟左右时间,而VPS可能需要数小时的时间来等待硬件修复。 在存储方面,存储节点损坏一两台服务器,并无任何影响,系统会自动将数据读写定向到其他节点。 而VPS是本机存储,一旦本机的硬盘或阵列损坏,轻则中断数小时时间,重则可能发生数据丢失情况。 三、看是否有独立IP 都有独立IP 部分服务商提供的是共享IP 有独立IP的不一定是真云,但使用共享IP的则一定是假云。所有共享IP的"云主机"就固定在那台机器上了,根本无法迁移至其他节点。 四、看是否支持内网和自定义镜像 支持 不支持 真云主机:天生支持内网链接 假云主机:极难支持。 内网链接的重要性,对于网站来说,相当重要!可以实现同一用户下的多台云主机之间相互通信、文件拷贝、搭建负载均衡等等诸多优势。 而VPS一般都是各个服务器单打独斗,不支持内网。 自定义镜像可以快速"克隆"出用户自定义的系统环境,必须在集群存储模式上才能使用;而VPS因为分散存储根本无法实现。 更多关于云主机与VPS的对比请访问:http://www.west263.com/services/CloudHost/vs.asp 很多小型的IDC公司为了借助云计算的热潮掘金,但短期内又无法掌握真正的云计算技术,便将VPS产品改头换面,直接打着"廉价云主机"的旗号吆喝,在损害中小企业用户利益的同时,也损害了整个市场的健康发展。 因此,用户在购买云主机时需擦亮双眼,尽量选择具有品牌知名度的服务商,切勿掉进商家"超低价"的陷阱。 据初步调查,目前国内在售的公有云中,真正实现了云计算的有:阿里云、盛大云、华为云、腾讯云、西部数码弹性云、Ucloud等不 超过10家企业,众多的IDC企业要想在云计算的大潮中分得一杯羹,光靠漫天过海的山寨做法是做不长久的,用户终有醒悟的一天。只有苦练内功,真正掌握云 计算的核心技术,才能持久地赢得用户和市场。 本文转自火地晋博客园博客,原文链接:http://www.cnblogs.com/yelaiju/p/3374976.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

面试侃集合 | SynchronousQueue公平模式篇

面试官:呦,小伙子来的挺早啊! Hydra:那是,不能让您等太久了啊(别废话了快开始吧,还赶着去下一场呢)。 面试官:前面两轮表现还不错,那我们今天继续说说队列中的SynchronousQueue吧。 Hydra:好的,SynchronousQueue和之前介绍过的队列相比,稍微有一些特别,必须等到队列中的元素被消费后,才能继续向其中添加新的元素,因此它也被称为无缓冲的等待队列。 我还是先写一个例子吧,创建两个线程,生产者线程putThread向SynchronousQueue中放入元素,消费者线程takeThread从中取走元素: SynchronousQueue<Integer>queue=newSynchronousQueue<>(true); ThreadputThread=newThread(()->{for(inti=0;i<=2;i++){try{ System.out.println("putthreadput:"+i); queue.put(i); System.out.println("putthreadput:"+i+"awake"); }catch(InterruptedExceptione){ e.printStackTrace(); } } }); ThreadtakeThread=newThread(()->{intj=0;while(j<2){try{ j=queue.take(); System.out.println("takefromputThread:"+j); }catch(InterruptedExceptione){ e.printStackTrace(); } } }); putThread.start(); Thread.sleep(1000); takeThread.start(); 执行上面的代码,查看结果: putthreadput:0takefromputThread:0putthreadput:0awakeputthreadput:1takefromputThread:1putthreadput:1awakeputthreadput:2takefromputThread:2putthreadput:2awake 可以看到,生产者线程在执行put方法后就被阻塞,直到消费者线程执行take方法对队列中的元素进行了消费,生产者线程才被唤醒,继续向下执行。简单来说运行流程是这样的: 面试官:就这?应用谁不会啊,不讲讲底层原理就想蒙混过关? Hydra:别急啊,我们先从它的构造函数说起,根据参数不同,SynchronousQueue分为公平模式和非公平模式,默认情况下为非公平模式 publicSynchronousQueue(booleanfair){ transferer=fair?newTransferQueue<E>():newTransferStack<E>(); } 我们先来看看公平模式吧,该模式下底层使用的是TransferQueue队列,内部节点由QNode构成,定义如下: volatileQNodenext;//nextnodeinqueuevolatileObjectitem;//CAS'edtoorfromnullvolatileThreadwaiter;//tocontrolpark/unparkfinalbooleanisData; QNode(Objectitem,booleanisData){this.item=item;this.isData=isData; } item用来存储数据,isData用来区分节点是什么类型的线程产生的,true表示是生产者,false表示是消费者,是后面用来进行节点匹配(complementary)的关键。在SynchronousQueue中匹配是一个非常重要的概念,例如一个线程先执行put产生了一个节点放入队列,另一个线程再执行take产生了一个节点,这两个不同类型的节点就可以匹配成功。 面试官:可是我看很多资料里说SynchronousQueue是一个不存储元素的阻塞队列,这点你是怎么理解的? Hydra:通过上面节点中封装的属性,可以看出SynchronousQueue的队列中封装的节点更多针对的不是数据,而是要执行的操作,个人猜测这个说法的出发点就是队列中存储的节点更多偏向于操作这一属性。 面试官:好吧,接着往下说队列的结构吧。 Hydra:TransferQueue中主要定义的属性有下面这些: transientvolatileQNodehead;transientvolatileQNodetail;transientvolatileQNodecleanMe; TransferQueue(){ QNodeh=newQNode(null,false);//initializetodummynode. head=h; tail=h; } 比较重要的有头节点head、尾节点tail、以及用于标记下一个要删除的节点的cleanMe节点。在构造函数初始化中创建了一个节点,注释中将它称为dummy node,也就是伪造的节点,它的作用类似于AQS中的头节点的作用,实际操作的节点是它的下一个节点。 要说SynchronousQueue,真是一个神奇的队列,不管你调用的是put和offer,还是take和poll,它都一概交给核心的transfer方法去处理,只不过参数不同。今天我们抛弃源码,通过画图对它进行分析,首先看一下方法的定义: Etransfer(Ee,booleantimed,longnanos); 面试官:呦呵,就一个方法?我倒要看看它是怎么区分实现的入队和出队操作… Hydra:在方法的参数中,timed和nanos用于标识调用transfer的方法是否是能够超时退出的,而e是否为空则可以说明是生产者还是消费者调用的此方法。如果e不为null,是生产者调用,如果e为null则是消费者调用。方法的整体逻辑可以分为下面几步: 1、若队列为空,或队列中的尾节点类型和自己的类型相同,那么准备封装一个新的QNode添加到队列中。在添加新节点到队尾的过程中,并没有使用synchronized或ReentrantLock,而是通过CAS来保证线程之间的同步。 在添加新的QNode到队尾前,会首先判断之前取到的尾节点是否发生过改变,如果有改变的话那么放弃修改,进行自旋,在下一次循环中再次判断。当检查队尾节点没有发生改变后,构建新的节点QNode,并将它添加到队尾。 2、当新节点被添加到队尾后,会调用awaitFulfill方法,会根据传递的参数让线程进行自旋或直接挂起。方法的定义如下,参数中的timed为true时,表示这是一个有等待超时的方法。 ObjectawaitFulfill(QNodes,Ee,booleantimed,longnanos); 在awaitFulfill方法中会进行判断,如果新节点是head节点的下一个节点,考虑到可能很快它就会完成匹配后出队,先不将它挂起,进行一定次数的自旋,超过自旋次数的上限后再进行挂起。如果不是head节点的下一个节点,避免自旋造成的资源浪费,则直接调用park或parkNanos挂起线程。 3、当挂起的线程被中断或到达超时时间,那么需要将节点从队列中进行移除,这时会执行clean()方法。如果要被删除的节点不是链表中的尾节点,那么比较简单,直接使用CAS替换前一个节点的next指针。 如果要删除的节点是链表中的尾节点,就会有点复杂了,因为多线程环境下可能正好有其他线程正在向尾节点后添加新的节点,这时如果直接删除尾节点的话,会造成后面节点的丢失。 这时候就会用到TransferQueue中定义的cleanMe标记节点了,cleanMe的作用就是当要被移除的节点是队尾节点时,用它来标记队尾节点的前驱节点。具体在执行过程中,又会分为两种情况: cleanMe节点为null,说明队列在之前没有标记需要删除的节点。这时会使用cleanMe来标识该节点的前驱节点,标记完成后退出clean方法,当下一次执行clean方法时才会删除cleanMe的下一个节点。 cleanMe节点不为null,那么说明之前已经标记过需要删除的节点。这时删除cleanMe的下一个节点,并清除当前cleanMe标记,并再将当前节点未修改前的前驱节点标记为cleanMe。注意,当前要被删除的节点的前驱节点不会发生改变,即使这个前驱节点已经在逻辑上从队列中删除掉了。 执行完成clean方法后,transfer方法会直接返回null,说明入队操作失败。 面试官:讲了这么多,入队的还都是一个类型的节点吧? Hydra:是的,TransferQueue队列中,只会存在一个类型的节点,如果有另一个类型的节点过来,那么就会执行出队的操作了。 面试官:好吧,那你接着再说说出队方法吧。 Hydra:相对入队来说,出队的逻辑就比较简单了。因为现在使用的是公平模式,所以当队列不为空,且队列的head节点的下一个节点与当前节点匹配成功时,进行出队操作,唤醒head节点的下一个节点,进行数据的传递。 根据队列中节点类型的不同,可以分为两种情况进行分析: 1、如果head节点的下一个节点是put类型,当前新节点是take类型。take线程取出put节点的item的值,并将其item变为null,然后推进头节点,唤醒被挂起的put线程,take线程返回item的值,完成数据的传递过程。 head节点的下一个节点被唤醒后,会推进head节点,虽然前面说过队列的head节点是一个dummy节点,并不存储数据,理论上应该将第二个节点直接移出队列,但是源码中还是将head节点出队,将原来的第二个节点变成了新的head节点。 2、同理,如果head节点的下一个节点是take类型,当前新节点是put类型。put线程会将take节点的item设为自己的数据值,然后推进头节点,并唤醒挂起的take线程,唤醒的take线程最终返回从put线程获得的item的值。 此外,在take线程唤醒后,会将自己QNode的item指针指向自己,并将waiter中保存的线程置为null,方便之后被gc回收。 面试官:也就是说,在代码中不一定非要生产者先去生产产品,也可以由消费者先到达后进行阻塞等待? Hydra:是的,两种线程都可以先进入队列。 面试官:好了,公平模式下我是明白了,我去喝口水,给你十分钟时间,回来我们聊聊非公平模式的实现吧。 Hydra:……

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册