首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

storm从入门到放弃(三),放弃使用 StreamId 特性

序:StreamId是storm中实现DAG有向无环图的重要一个特性,但是从实际生产环境来看,这个功能其实蛮影响生产环境的稳定性的,我们系统在迭代时会带来整体服务的不可用。 StreamId是storm中实现DAG有向无环图的重要一个特性,官方也提供对应的接口实现让开发者自己灵活化构造自己的ADG图。但是从我这一年从事流式计算的工作中得到的结果也很尴尬的,很多人不知道storm的这一个特性,甚至某些数据中也没有提及。当然这也比较幸运,不知道这个特性就可以少踩点坑了。因为从实际生产环境来看,这个功能其实蛮影响生产环境的稳定性的,为什么这么说,hey,hey,look dowm。 原文和作者一起讨论:http://www.cnblogs.com/intsmaze/p/7283442.html 实际开发中,很多人没有用streamid,其实只是没有显示指定罢了,默认streamid的名称为default,这也就是为什么消息可以由一个bolt发往另一个bolt了。我们自己显示指定streamid可以实现进入某一个bolt的消息,某些消息发给下游的Abolt,另一些消息发给下游的Bbolt。 比如有这样一个需求砸向你的脸上,有很多其他系统的消息发送到kafka某一个主题中,现在用storm去kafka消费该主题,在bolt-业务这个节点进行消息类型的判断,然后根据判断将消息发送到不同的下游bolt进行处理以便将这些消息发往不同的渠道接口中。这样一个需求我们利用streamid很容易实现,看起来也没有什么问题。关于sreamid的使用可以文章末尾。 为什么在实际生产我不建议这样使用,生产中经常会面对迭代开发的情况,业务不断的变化,你的代码也要不断的修改,第三方接口的变动,你也要不断的修改与第三方交互的程序。如果这周要修改bolt-微信,然后到发布的时候,你必须停掉整个拓扑任务这明显不是我们想要的,我们期望的是只停掉bolt-微信而不影响其他的业务线。这个时候就会发现这个实现方式很鸡肋的。那我们应该怎么做,看一下我在某信用卡中心的实现方案,看了后,你会替我庆幸我没有为了图前期的简单而采用显示streamid导致后面每该一处很小的功能导致整个拓扑任务不提供服务一段时间。 我们的系统会收到交易信息,然后根据业务bolt进行处理,然后形成话术推送给不同的渠道bolt,这些渠道bolt对接各个部门(这些部门接受到我们的话术后,将话术推送给微信用户,支付宝用户等),而我们的对外渠道多大15个左右。同时应为业务的不断提出,以及对接部门接口的变化我们这些渠道bolt也要跟随变化。所以我们在业务bolt和渠道bolt中引入了第三方消息系统kafka队列,而不是用storm内部的Disruptor队列。这样原本一个拓扑任务,我们进行拆分为一个业务拓扑,以及多个其渠道拓扑,渠道拓扑与业务拓扑通信通过kafka的主题来协调。如果某一天我们要修改微信渠道的业务,我们只需要停掉微信拓扑即可,整个系统并不会受到影响,原本推送给微信渠道的消息也不会因此丢失它保存在kafka主题中,一旦微信拓扑上线即可立马消费掉。 后话,我这样说有点绝对了,具体看系统的情况来权衡。 streamid在storm中的正确打开方式。 public class ProduceRecordSpout extends BaseRichSpout { private static final long serialVersionUID = 1L; private SpoutOutputCollector collector; private String recordLines; private String type; public ProduceRecordSpout(String type, String lines) { this.type = type; recordLines = lines; } public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) { this.collector = collector; }public void nextTuple() { Utils.sleep(5000); System.out.println("record is "+recordLines); List<Object> values = new Values(type, recordLines); collector.emit(values, values); } public void declareOutputFields(OutputFieldsDeclarer declarer) { declarer.declare(new Fields("type", "record")); } } public class DistributeByTypeBolt extends BaseRichBolt { private static final long serialVersionUID = 1L; private OutputCollector collector; public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) { this.collector = collector; } public void execute(Tuple input) { String type = input.getString(0); String word = input.getString(1); switch (type) { case Type.NUMBER: collector.emit("stream-number-saver", input, new Values(type, word)); collector.emit(input, new Values("other", "message coming")); break; case Type.STRING: collector.emit("stream-string-saver", input, new Values(type, word)); collector.emit(input, new Values("other", "message coming")); break; default: collector.emit(input, new Values(type, word)); } collector.ack(input); } public void declareOutputFields(OutputFieldsDeclarer declarer) { declarer.declareStream("stream-number-saver", new Fields("type", "word")); declarer.declareStream("stream-string-saver", new Fields("type", "word")); declarer.declare(new Fields("type", "word")); } } public class SaveBolt extends BaseRichBolt { private static final long serialVersionUID = 1L; private OutputCollector collector; public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) { this.collector = collector; } public void execute(Tuple input) { System.out.println("个人微信:intsmaze"+ "SourceComponent=" + input.getSourceComponent() + ", SourceStreamId=" + input.getSourceStreamId() + ", type=" + input.getString(0) + ", value=" + input.getString(1)); } public void declareOutputFields(OutputFieldsDeclarer declarer) { } } public class SaveDefaultBolt extends BaseRichBolt { private static final long serialVersionUID = 1L; private OutputCollector collector; public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) { this.collector = collector; } public void execute(Tuple input) { System.out.println("个人微博:猥琐发育的码农"+ "SourceComponent=" + input.getSourceComponent() + ", SourceStreamId=" + input.getSourceStreamId() + ", type=" + input.getString(0) + ", value=" + input.getString(1)); } public void declareOutputFields(OutputFieldsDeclarer declarer) { } } public class SaveTwoBolt extends BaseRichBolt { private static final long serialVersionUID = 1L; private OutputCollector collector; public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) { this.collector = collector; } public void execute(Tuple input) { System.out.println("博客链接:http://www.cnblogs.com/intsmaze/p/7283442.html"+ "SourceComponent=" + input.getSourceComponent() + ", SourceStreamId=" + input.getSourceStreamId() + ", type=" + input.getString(0) + ", value=" + input.getString(1)); } public void declareOutputFields(OutputFieldsDeclarer declarer) { } } public class StreamTopologyMain { public static void main(String[] args) throws Exception { TopologyBuilder builder = new TopologyBuilder(); builder.setSpout("spout-number", new ProduceRecordSpout(Type.NUMBER, "80966 31"), 1); builder.setSpout("spout-string", new ProduceRecordSpout(Type.STRING, "hello the word"), 1); builder.setBolt("bolt-distributor", new DistributeByTypeBolt(), 2) .shuffleGrouping("spout-number") .shuffleGrouping("spout-string"); builder.setBolt("bolt-number-saver", new SaveBolt(), 1).shuffleGrouping("bolt-distributor", "stream-number-saver"); builder.setBolt("bolt-string-saver", new SaveTwoBolt(), 1).shuffleGrouping("bolt-distributor", "stream-string-saver"); builder.setBolt("bolt-default-saver", new SaveDefaultBolt(), 1).shuffleGrouping("bolt-distributor"); Config conf = new Config(); conf.setDebug(false); String name = StreamTopologyMain.class.getSimpleName(); LocalCluster cluster = new LocalCluster(); cluster.submitTopology(name, conf, builder.createTopology()); Thread.sleep(60 * 60 * 1000); cluster.shutdown(); } } interface Type { String NUMBER = "NUMBER"; String STRING = "STRING"; } 作者: intsmaze(刘洋) 出处: http://www.cnblogs.com/intsmaze/ 老铁,你的--->推荐,--->关注,--->评论--->是我继续写作的动力。 微信公众号号:Apache技术研究院 由于博主能力有限,文中可能存在描述不正确,欢迎指正、补充! 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

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

hadoop入门之设置datanode的心跳时间的方法

做作业的过程中发现,把一节点停掉,dfsadmin和50070都无法马上感知到一个data node已经死掉 HDFS默认的超时时间为10分钟+30秒。 这里暂且定义超时时间为timeout 计算公式为: timeout= 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval 而默认的heartbeat.recheck.interval 大小为5分钟,dfs.heartbeat.interval默认的大小为3秒。 需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒 所以,举个例子,如果heartbeat.recheck.interval设置为5000(毫秒),dfs.heartbeat.interval设置为3(秒,默认),则总的超时时间为40秒 <property> <name>heartbeat.recheck.interval</name> <value>5000</value> </property> <property> <name>dfs.heartbeat.interval</name> <value>3</value> </property> 参考http://f.dataguru.cn/thread-128378-1-1.html -------------------------- Linux环境:CentOs6.4 Hadoop版本:Hadoop-1.1.2 master: 192.168.1.241 NameNode JobTracker DataNode TaskTracker slave:192.168.1.242 DataNode TaskTracker 内容:设置DataNode的心跳,当某一个节点失去连接之后,在超过设置的时间,看hadoop能否正常工作。 设置时间: 复制代码 代码如下: <property> <name>heartbeat.recheck.interval</name> <value>15</value> </property> 第一步: 配置hdfs-site.xml 第二步:重启Hadoop 第三步:通过网页浏览两个节点的状态。 hadoop两个节点都已正常运行。 第三步:杀死主节点的进程,等待15秒。 通过kill命令杀死master上的DataNode节点。 第四步:查看节点状态 活着的DataNode还有1个,死亡的DataNode一个 master上的DataNode节点已经标识为Dead 只剩下slave节点,其最后连接时间是2秒(Last Contact 2) 杀死一个节点,两一个节点仍能够正常查看文件信息。 只有slave节点在运行。 http://www.jb51.net/softjc/137250.html 本文转自茄子_2008博客园博客,原文链接:http://www.cnblogs.com/xd502djj/p/4645298.html,如需转载请自行联系原作者。

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

Gradle for Android第二篇( Build.gradle入门 )

在这一章,我们将学习以下内容: 理解Gradle文件 编写简单的构建任务 自制构建脚本 理解Gradle脚本 当然我们现在讨论的所有内容都是基于Android studio的,所以请先行下载相关工具。当我们创建一个新的工程,Android studio会默认为我们创建三个gradle文件,两个build.gradle,一个settings.gradle,build.gradle分别放在了根目录和moudle目录下,下面是gradle文件的构成图: MyApp ├──build.gradle ├──settings.gradle └──app └──build.gradle setting.gradle解析 当你的app只有一个模块的时候,你的setting.gradle将会是这样子的: include':app' setting.gradle文件将会在初始化时期执行,关于初始化时期,可以查看上一篇博客,并且定义了哪一个模块将会被构建。举个例子,上述setting.gradle包含了app模块,setting.gradle是针对多模块操作的,所以单独的模块工程完全可以删除掉该文件。在这之后,Gradle会为我们创建一个Setting对象,并为其包含必要的方法,你不必知道Settings类的详细细节,但是你最好能够知道这个概念。 根目录的build.gradle 该gradle文件是定义在这个工程下的所有模块的公共属性,它默认包含二个方法: buildscript{ repositories{ jcenter() } dependencies{ classpath'com.android.tools.build:gradle:1.2.3' } } allprojects{ repositories{ jcenter() } } buildscript方法是定义了全局的相关属性,repositories定义了jcenter作为仓库。一个仓库代表着你的依赖包的来源,例如maven仓库。dependencies用来定义构建过程。这意味着你不应该在该方法体内定义子模块的依赖包,你仅仅需要定义默认的Android插件就可以了,因为该插件可以让你执行相关Android的tasks。 allprojects方法可以用来定义各个模块的默认属性,你可以不仅仅局限于默认的配置,未来你可以自己创造tasks在allprojects方法体内,这些tasks将会在所有模块中可见。 模块内的build.gradle 模块内的gradle文件只对该模块起作用,而且其可以重写任何的参数来自于根目录下的gradle文件。该模块文件应该是这样: applyplugin:'com.android.application' android{ compileSdkVersion22 buildToolsVersion"22.0.1" defaultConfig{ applicationId"com.gradleforandroid.gettingstarted" minSdkVersion14 targetSdkVersion22 versionCode1 versionName"1.0" } buildTypes{ release{ minifyEnabledfalse proguardFilesgetDefaultProguardFile ('proguard-android.txt'),'proguard-rules.pro' } } } dependencies{ compilefileTree(dir:'libs',include:['*.jar']) compile'com.android.support:appcompat-v7:22.2.0' } 插件 该文件的第一行是Android应用插件,该插件我们在上一篇博客已经介绍过,其是google的Android开发团队编写的插件,能够提供所有关于Android应用和依赖库的构建,打包和测试。 Android 该方法包含了所有的Android属性,而唯一必须得属性为compileSdkVersion和buildToolsVersion: compileSdkVersion:编译该app时候,你想使用到的api版本。 buildToolsVersion:构建工具的版本号。 构建工具包含了很多实用的命令行命令,例如aapt,zipalign,dx等,这些命令能够被用来产生多种多样的应用程序。你可以通过sdk manager来下载这些构建工具。 defaultConfig方法包含了该app的核心属性,该属性会重写在AndroidManifest.xml中的对应属性。 defaultConfig{ applicationId"com.gradleforandroid.gettingstarted" minSdkVersion14 targetSdkVersion22 versionCode1 versionName"1.0" } 第一个属性是applicationId,该属性复写了AndroidManifest文件中的包名package name,但是关于applicationId和package name有一些不同。在gradle被用来作为Android构建工具之前,package name在AndroidManifest.xml有两个作用:其作为一个app的唯一标示,并且其被用在了R资源文件的包名。 Gradle能够很轻松的构建不同版本的app,使用构建变种。举个例子,其能够很轻松的创建一个免费版本和付费版本的app。这两个版本需要分隔的标示码,所以他们能够以不同的app出现在各大应用商店,当然他们也能够同时安装在一个手机中。资源代码和R文件必须拥有相同的包名,否则你的资源代码将需要改变,这就是为什么Android开发团队要将package name的两大功能拆分开。在AndroidManifest文件中定义的package name依然被用来作为包名和R文件的包名。而applicationid将被用在设备和各大应用商店中作为唯一的标示。 接下来将是minSdkVersion和targetSdkVersion。这两个和AndroidManifest中的<uses-sdk>很像。minSdkVersion定义为最小支持api。 versionCode将会作为版本号标示,而versionName毫无作用。 所有的属性都是重写了AndroidManifest文件中的属性,所以你没必要在AndroidManifest中定义这些属性了。 buildTypes方法定义了如何构建不同版本的app,我们将在下一篇博客中有所介绍。 依赖包 依赖模块作为gradle默认的属性之一(这也是为什么其放在了Android的外面),为你的app定义了所有的依赖包。默认情况下,我们依赖了所有在libs文件下的jar文件,同时包含了AppCompat这个aar文件。我们将会在下一篇博客中讨论依赖的问题。 让我们开始tasks吧 如果你想知道你多少tasks可以用,直接运行gradlew tasks,其会为你展示所有可用的tasks。当你创建了一个Android工程,那么将包含Android tasks,build tasks,build setup tasks,help tasks,install tasks,verification tasks等。 基本的tasks android插件依赖于Java插件,而Java插件依赖于base插件。 base插件有基本的tasks生命周期和一些通用的属性。 base插件定义了例如assemble和clean任务,Java插件定义了check和build任务,这两个任务不在base插件中定义。 这些tasks的约定含义: assemble: 集合所有的output clean: 清除所有的output check: 执行所有的checks检查,通常是unit测试和instrumentation测试 build: 执行所有的assemble和check Java插件同时也添加了source sets的概念。 Android tasks android插件继承了这些基本tasks,并且实现了他们自己的行为: assemble 针对每个版本创建一个apk clean 删除所有的构建任务,包含apk文件 check 执行Lint检查并且能够在Lint检测到错误后停止执行脚本 build 执行assemble和check 默认情况下assemble tasks定义了assembleDebug和assembleRelease,当然你还可以定义更多构建版本。除了这些tasks,android 插件也提供了一些新的tasks: connectedCheck 在测试机上执行所有测试任务 deviceCheck 执行所有的测试在远程设备上 installDebug和installRelease 在设备上安装一个特殊的版本 所有的install task对应有uninstall 任务 build task依赖于check任务,但是不依赖于connectedCheck或者deviceCheck,执行check任务的使用Lint会产生一些相关文件,这些报告可以在app/build/outputs中查看: android studio的tasks 你根本不必要去执行gradle脚本在命令行中,Android studio有其对应的工具: 在这个界面,你要做的就是双击了。当然你也可以在Android studio中打开命令行,执行相关命令,具体操作就不介绍了。 自定义构建 当你在Android studio中自定义了gradle文件,需要更新project: 其实该按钮,执行了generateDebugSources tasks,该任务会生成所有必要的classes文件。 BuildConfig和resources android{ buildTypes{ debug{ buildConfigField"String","API_URL", "\"http://test.example.com/api\"" buildConfigField"boolean","LOG_HTTP_CALLS","true" } release{ buildConfigField"String","API_URL", "\"http://example.com/api\"" buildConfigField"boolean","LOG_HTTP_CALLS","false" } } 类似这些定义的常量,当定义了这些属性后,你完全可以在代码中使用:BuildConfig.API_URL和BuildConfig.LOG_HTTP 最近,Android tools team也让其里面定义string变为可能: android{ buildTypes{ debug{ resValue"string","app_name","ExampleDEBUG" } release{ resValue"string","app_name","Example" } } } 你可以在代码中使用这些string。其中“”不是必须得。 全局设置 如果你有很多模块在一个工程下,你可以这么定义你的project文件。 allprojects{ applyplugin:'com.android.application' android{ compileSdkVersion22 buildToolsVersion"22.0.1" } } 这只会在你的所有模块都是Android app应用的时候有效。你需要添加Android 插件才能访问Android的tasks。更好的做法是你在全局的gradle文件中定义一些属性,然后再模块中运用它们。比如你可以在根目录下这么定义: ext{ compileSdkVersion=22 buildToolsVersion="22.0.1" 那么你在子模块中就可以使用这些属性了: android{ compileSdkVersionrootProject.ext.compileSdkVersion buildToolsVersionrootProject.ext.buildToolsVersion } Project properties文件 上述方法是一种办法,当然还有很多办法: ext方法 gradle.properties文件 -p参数 ext{ local='Hellofrombuild.gradle' } taskprintProperties<<{ printlnlocal//Localextraproperty printlnpropertiesFile//Propertyfromfile if(project.hasProperty('cmd')){ printlncmd//Commandlineproperty } } 当然你可以在gradle.properties中定义: propertiesFile=Hellofromgradle.properties 你也可以输入命令行: $gradlewprintProperties-Pcmd='Hellofromthecommandline' :printProperties Hellofrombuild.gradle Hellofromgradle.properties Hellofromthecommandline 总结 在这篇博客中,我们细致的查看了Android studio生成的三个gradle文件,现在你应该能够自己去创建自己的gradle文件,我们还学习了最基本的构建任务,学习了Android 插件以及其tasks。 在接下来的几年里,Android开发生态将会爆炸性增长,很多有趣的依赖库将会让每个人去使用,在下一篇博客里面,我们将看看我们能有几种方式添加我们的依赖库,这样我们才能够避免造轮子。 本文作者:佚名 来源:51CTO

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

SpringMVC札集(02)——SpringMVC入门完整详细示例(下)

自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 自定义View系列教程08–滑动冲突的产生及其处理 探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)— 核心基础 Android多分辨率适配框架(2)— 原理剖析 Android多分辨率适配框架(3)— 使用指南 在上一篇中,我们完成了一个SpringMVC的HelloWorld。在这个示例中我们使用的系统默认的HandlerMapping和HandlerAdapter即BeanNameUrlHandlerMapping和SimpleUrlHandlerMapping。在本篇博客中我们再来瞅瞅其他的HandlerMapping和HandlerAdapter。 SimpleUrlHandlerMapping SimpleUrlHandlerMapping用于将url与Controller相对应。 <!-- 自定义Controller --> <bean id="myController" name="/welcome.do" class="cn.com.MyController"></bean> <!-- 简单处理器映射器 --> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/hello.do">myController</prop> <prop key="/hi.do">myController</prop> </props> </property> </bean> 在此先配置我们的自定义Controller,然后利用SimpleUrlHandlerMapping配置映射。在该配置中,将/hello.do和/hi.do都映射至myController。所以,当我们在浏览器中输入http://localhost:8081/SpringMVC02/hi.do或者http://localhost:8081/SpringMVC02/hello.do都会执行到MyController ControllerClassNameHandlerMapping 相对于前两种处理映射器,ControllerClassNameHandlerMapping就显得简单多了,在配置ControllerClassNameHandlerMapping后,我们只需在浏览器中输入Controller对应的名字.do就行,但是务必注意其第一个字母必须小写。 <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"></bean> 比如:http://localhost:8081/SpringMVC02/myController.do 嗯哼,至此SpringMVC常见的三种处理器映射器就已经介绍完了;我们可依据需求在springmvc.xml中配置;三者可共存,不会冲突。 HttpRequestHandlerAdapter 在上一篇博客中我们的MyController实现了Controller接口,使用的是SimpleControllerHandlerAdapter做为处理器适配器执行Controller。除此以外,可让我们的Controller实现HttpRequestHandler接口,比如:MyHttpController implements HttpRequestHandler,此时可用HttpRequestHandlerAdapter做为处理器适配器执行Controller。请看如下示例: /** * @author 原创作者:谷哥的小弟 * @blog 博客地址:http://blog.csdn.net/lfdfhl * @time 创建时间:2017年7月25日 下午10:02:30 * @info 描述信息:实现了HttpRequestHandler接口的Controller */ package cn.com; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.HttpRequestHandler; public class MyHttpController implements HttpRequestHandler { @Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setAttribute("helloSpringMVC", "实现了HttpRequestHandler接口的Controller"); request.getRequestDispatcher("/WEB-INF/jsps/test.jsp").forward(request, response); } } 在此实现一个Controller <!-- 处理器适配器 --> <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean> 再在springmvc.xml中配置处理器适配器 最后,在浏览器访问http://localhost:8081/SpringMVC02/httpController.do即可 关于SpringMVC常用的处理器映射器和处理器适配器就介绍到此。

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

《 Java并发编程从入门到精通》目录和序言

目 录 第一部分:线程并发基础 第1章 概念部分 1 1.1 CPU核心数、线程数 (主流cpu,线程数的大体情况说一下) 1 1.2 CPU时间片轮转机制 2 1.3 什么是进程和什么是线程 4 1.4 进程和线程的比较 5 1.5 什么是并行运行 7 1.6 什么是多并发运行8 1.7 什么是吞吐量 9 1.8 多并发编程的意义及其好处和注意事项10 1.9 分布式与并发运算关系 11 1.10 Linux和Window多并发可以采取不的一样机制(apache和tomcat??) 6 第2章 认识Java里面的Thread 12 2.1 线程的实现三种方法 (先感受一下创建几个多线程方法实例演练)12 2.2 Thread里面的属性和方法 (通过工具看看能不能监控到thread里面的一些属性值)16 2.3 线程的生命周期 19 2.4 什么是守护线程 31 2.5 线程组 33 2.6 当前线程副本ThreadLocal(用意和实际应用场景) 35 2.7 线程异常的处理(单个和组)38 第3章 Thread安全 39 3.0 线程的内存模型 3.1 什么是不安全(写个代码例子多并发带来的一些问题,变量互串,相互影响) 39 3.2 什么是安全(写个代码例子,安全的三种(多实例,加锁,线程安全的集合类)情况,引出锁) 43 3.3 第一种锁:隐式锁,又称线程同步synchronized(举几个例子实际演示一下,及其写法注意,带来的额外开销) 45 3.4 第二种锁:显示锁,Lock;及其与synchronized的区别(ReentrantReadWriteLock) 49 3.5 什么是死锁 53 3.6 看如下代码的锁有用吗 55 3.7 关键字:volatile 57 3.8 原子操作:atomic(atomic包FutureTask, AtomicLong等) 59 3.9 线程同步和锁的原理(有待弄清楚锁的运行机制和原理) 61 3.10 单利模式的写法 63 第4章 线程安全的集合类 64 4.1 java.util.concurrent. ConcurrentMap 64 4.2 java.util.concurrent.ConcurrentHashMap 66 4.3 java.util.concurrent. CopyOnWriteArrayList 68 4.4 java.util.concurrent. CopyOnWriteArraySet 70 4.5 非concurrent下面的线程安全集合类(Hashtable 和 Vector 和StringBuffer) 72 4.6 集合类安全的实现原理剖析 75 第二部分:线程并发晋级之高级部分 75 第5章 多线程之间交互:线程阀 5.1 线程安全的阻塞队列BlockingQueue (详解一翻java.util.concurrent.ConcurrentLinkedDeque 和java.util.concurrent. ConcurrentLinkedQueue) 76 5.2 同步计数器CountDownLatch 81 5.3 循环障碍CyclicBarrier 84 5.4 信号装置Semaphore 87 5.5 任务机制FutureTask 90 第6章 线程池 115 6.1 什么是线程池 90 6.2 newFixedThreadPool的使用 92 6.3 newCachedThreadPool 的使用 94 6.4 newSingleThreadExecutor的使用(插图,原理) 96 6.5 线程池的好处(未使用的时候的情况,使用后的情况) 98 6.4 认识ExecutorService(ThreadFactory先创建一个线程及其参数的详细讲解,如何自定义线程池) 100 6.5 线程池的原理 106 6.6 线程池在工作中的错误使用 112 第7章 JDK7新增的Fork/Join 115 7.1 什么是Fork/Join 架构 115 7.2 创建实际使用Fork/Join 线程池118 7.3 合并任务的结果 123 7.4 工作原理 126 7.5 异步运行任务 130 7.6 在任务中抛出异常 135 7.7 结束任务 140 7.8 实际应用场景 143 第三部分:实际的使用与监控与拓展 第8章 线程,线程池在实际互联网项目开发中的应用 8.1 Servlet线程的设计 8.2 线程池如何合理设计与设置 8.3 Tomcat中线程池如何合理设置 8.4 Nginx线程池 8.5 数据库连接池 8.6 工作中如何实现在分布式系统中实现高并发 第9章 线程的监控及其日常工作中如何分析 9.1Java线程池的监控 9.2 ForkJoin的监控 9.3 Java内存模型 9.4 可视化监控工具的使用 9.5 Linux线程分析监控使用方法 9.6 Linux分析监控的运行脚本 9.7 Eclipse里面如何调试并发程序 9.8 如何通过压力测试,测试服务器的抗压能力 9.9MultithreadedTC测试并发简单介绍 第10章 线程在Android开发中的体现 10.1Android进程的基本知识 10.2Android进程的生命周期 10.3Android中Activity的生命周期 10.4Android线程的运行机制 10.5Android异步线程的处理方法 10.6Android异步线程的原理与实现 附录一:JVM的参数 附录二:Jstat的语法 附录三:Jstat中的一些术语的中文解释 附录四:Tomcat里面的server.xml中Executor的参数 附录五:Thread的API 结束语 序言 古时候,有一个自认为佛学造诣很深的人,听说某个寺庙里有位德高望重的老禅师,便去拜访。老禅师十分恭敬地接待了他,他讲了自己的很多心得,希望老禅师给予指点。 老禅师听后,没有说话,只是为他沏茶。可是在倒水时,明明水已经满了,老禅师还在倒,而不顾茶水都已经溢了出来。最后,这个人终于忍不住说:“大师,杯子已经满了。”老禅师这才住手。这个人问老禅师:“大师,请你指点。”老禅师说:“我已经教你了。”这个人不明所以,只好回去了。冥思苦想,终于有一天他想明白了:如果自己不把旧茶倒掉,又哪有空间来添续新茶? 空杯心态不仅是一种心境,更是一种做人的境界。其实我们学习,和看任何一本书的时候相信如果以空杯的心态去看的话,相信收获会更多。功夫巨星李小龙就非常推崇空杯心态,他说:“清空你的杯子,方能再行注满,空无以求全。” 最近发现市面上有些书籍要不就是直译过来的,很多不实用,要不就是讲的太玄乎其神了,而此书换一种方式,换一种思路来理解多并发和多线程,让多线,多并发没有那么玄乎;这本书读完让你菜鸟变大牛。作者以10年的开发经验做总结,希望能帮助读者少走一些弯路。本书有浅入深再到实际。作者建议大家,不要动不动就Hadoop,动不动就分布式,其实将Java里面的多并发编程学习好了,其实就可以解决很多的问题的。 建议大家看此书的时候,结合JDK的源码,一起看,每个实例都要运行看看,还有看看咱们工作中,相关的设计是否合理。纸上得来终觉浅,绝知此事要躬行。一定要多加练习才行。 精彩书评: 对于一个初学者,或者是工作了几年的java工程师来说,通过详细的读此书,相信都一定会有或多或少的收获,看到Jack(即作者)几个月来的辛勤的劳动成功,表示感到钦佩。本书几乎涵盖了所有Java多并发,多线程开发相关的学习资料。相信此书一定会成为一个很好的多并发方面的,书不离手的开发手册。 –Steve.Xiu [10年Java工作经验,现就职于alibaba高级开发] 韩愈有言“师者,传道受业解惑也”,读完此书,对作者肃然起敬,他不正是秉承了这样的师道在作此书嘛!十多年的开发经验倾囊相授,言之谆谆,例之凿凿,实为难得。对Java多线程的知识讲解得如此详尽,如此深入,给人一种一览众山小的感觉。期待更多力作面世! –XiaoShuang.Li(李小双) [10年Java工作经验,知名互联网公司项目经理] 我在IT软件行业从业已12年。作为“前辈”,衡量一名“程序猿”的技术实力,一般会看你是否具备深度的系统性能调优的能力。云计算的时代,对系统的高性能、高并发要求更高。所以,深入了解和掌握Java的多线程机制原理,非常有用,非常必要。 这本书的所有知识均来自于作者多年的项目实践,倾注了作者多年的心血。讲解的深入浅出,让你掌握起来毫不费力。如果你想成为一名架构师,如果你想成为一名资深的技术大牛,强烈推荐你读一读,你值得拥有! –Justin.Han(韩剑锋) [12年Java工作经验,曾在多家IT公司担任研发总监、技术总监] 在进行并发编程开发之前,深入的学习并发理论知识非常有必要,比如阅读并发容器的源码,本书通过大量代码实例,讲解并发知识,非常细致。而在实战中并发程序的问题定位也是非常麻烦,相信本书的第九章能给初学者一些参考。 –Kiral(方腾飞) [ 方腾飞,阿里巴巴资深开发工程师, ifeve.com创始人] 感谢: 书上有一部分内容都是有网友精彩提供,在此表示感谢!也谢谢那些精彩书评的朋友,谢谢大家的支持。 转载自并发编程网 - ifeve.com

资源下载

更多资源
Mario

Mario

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

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

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

用户登录
用户注册