java编程规范的一个小问题?

后使用快捷导航没有帐号?
查看: 8|回复: 0
java在处理大数据的时候一些小技巧
注册会员, 积分 195, 距离下一级还需 5 积分
论坛徽章:1
众所周知, Java 在处理数据量比较大的时候,加载到内存必然会导致内存溢出,而在一些数据处理中我们不得不去处理海量数据,在做数据处理中,我们常见的手段是分解,压缩,并行,临时文件等方法;例如,我们要将 数据库 (不论是什么数据库)的数据导出到一个文件,一般是Excel或文本格式的CSV;对于Excel来讲,对于POI和JXL的接口,你很多时候没有办法去控制内存什么时候向磁盘写入,很恶心,而且这些API在内存构造的对象大小将比数据原有的大小要大很多倍数,所以你不得不去拆分Excel,还好,POI开始意识到这个问题,在3.8.4的版本后,开始提供cache的行数,提供了SXSSFWorkbook的接口,可以设置在内存中的行数,不过可惜的是,他当你超过这个行数,每添加一行,它就将相对行数前面的一行写入磁盘(如你设置2000行的话,当你写第20001行的时候,他会将第一行写入磁盘),其实这个时候他些的临时文件,以至于不消耗内存,不过这样你会发现,刷磁盘的频率会非常高,我们的确不想这样,因为我们想让他达到一个范围一次性将数据刷如磁盘,比如一次刷1M之类的做法,可惜现在还没有这种API,很痛苦,我自己做过测试,通过写小的Excel比使用目前提供刷磁盘的API来写大文件,效率要高一些,而且这样如果访问的人稍微多一些磁盘IO可能会扛不住,因为IO资源是非常有限的,所以还是拆文件才是上策;而当我们写CSV,也就是文本类型的文件,我们很多时候是可以自己控制的,不过你不要用CSV自己提供的API,也是不太可控的,CSV本身就是文本文件,你按照文本格式写入即可被CSV识别出来;如何写入呢?下面来说说。。。在处理数据层面,如从数据库中读取数据,生成本地文件,写代码为了方便,我们未必要1M怎么来处理,这个交给底层的驱动程序去拆分,对于我们的程序来讲我们认为它是连续写即可;我们比如想将一个1000W数据的数据库表,导出到文件;此时,你要么进行分页,oracle当然用三层包装即可, MySQL 用limit,不过分页每次都会新的查询,而且随着翻页,会越来越慢,其实我们想拿到一个句柄,然后向下游动,编译一部分数据(如10000行)将写文件一次(写文件细节不多说了,这个是最基本的),需要注意的时候每次buffer的数据,在用outputstream写入的时候,最好flush一下,将缓冲区清空下;接下来, 执行一个没有where条件的SQL,会不会将内存撑爆 ?是的,这个问题我们值得去思考下,通过API发现可以对SQL进行一些操作,例如,通过:PreparedStatement statement = connection.prepareStatement(sql),这是默认得到的预编译,还可以通过设置:PreparedStatement statement = connection.prepareStatement(sql , ResultSet.TYPE_FORWARD_ONLY , ResultSet.CONCUR_READ_ONLY);来设置游标的方式,以至于游标不是将数据直接cache到本地内存,然后通过设置statement.setFetchSize(200);设置游标每次遍历的大小;OK,这个其实我用过,oracle用了和没用没区别,因为oracle的jdbc API默认就是不会将数据cache到java的内存中的,而mysql里头设置根本无效, 我上面说了一堆废话,呵呵 ,我只是想说,java提供的标准API也未必有效,很多时候要看厂商的实现机制,还有这个设置是很多网上说有效的,但是这纯属抄袭;对于oracle上面说了不用关心,他本身就不是cache到内存,所以java内存不会导致什么问题,如果是mysql,首先必须使用5以上的版本,然后在连接参数上加上useCursorFetch=true这个参数,至于游标大小可以通过连接参数上加上:defaultFetchSize=1000来设置,例如:jdbc:mysql://xxx.xxx.xxx.xxx:3306/abc?zeroDateTimeBehavior=convertToNull&useCursorFetch=true&defaultFetchSize=1000上次被这个问题纠结了很久(mysql的数据老导致程序内存膨胀,并行2个直接系统就宕了),还去看了很多源码才发现奇迹竟然在这里,最后经过mysql文档的确认,然后进行测试,并行多个,而且数据量都是500W以上的,都不会导致内存膨胀,GC一切正常,这个问题终于完结了。我们再聊聊其他的,数据拆分和合并,当数据文件多的时候我们想合并,当文件太大想要拆分,合并和拆分的过程也会遇到类似的问题,还好,这个在我们可控制的范围内,如果文件中的数据最终是可以组织的,那么在拆分和合并的时候,此时就不要按照数据逻辑行数来做了,因为行数最终你需要解释数据本身来判定,但是只是做拆分是没有必要的,你需要的是做二进制处理,在这个二进制处理过程,你要注意了,和平时read文件不要使用一样的方式,平时大多对一个文件读取只是用一次read操作,如果对于大文件内存肯定直接挂掉了,不用多说,你此时因该每次读取一个可控范围的数据,read方法提供了重载的offset和length的范围,这个在循环过程中自己可以计算出来,写入大文件和上面一样,不要读取到一定程序就要通过写入流flush到磁盘;其实对于小数据量的处理在现代的NIO技术的中也有用到,例如多个终端同时请求一个大文件下载,例如视频下载吧,在常规的情况下,如果用java的容器来处理,一般会发生两种情况:其一为内存溢出,因为每个请求都要加载一个文件大小的内存甚至于更多,因为java包装的时候会产生很多其他的内存开销,如果使用二进制会产生得少一些,而且在经过输入输出流的过程中还会经历几次内存拷贝,当然如果有你类似nginx之类的中间件,那么你可以通过send_file模式发送出去,但是如果你要用程序来处理的时候,内存除非你足够大,但是java内存再大也会有GC的时候,如果你内存真的很大,GC的时候死定了,当然这个地方也可以考虑自己通过直接内存的调用和释放来实现,不过要求剩余的物理内存也足够大才行,那么足够大是多大呢?这个不好说,要看文件本身的大小和访问的频率;其二为假如内存足够大,无限制大,那么此时的限制就是线程,传统的IO模型是线程是一个请求一个线程,这个线程从主线程从线程池中分配后,就开始工作,经过你的Context包装、Filter、拦截器、业务代码各个层次和业务逻辑、访问数据库、访问文件、渲染结果等等,其实整个过程线程都是被挂住的,所以这部分资源非常有限,而且如果是大文件操作是属于IO密集型的操作,大量的CPU时间是空余的,方法最直接当然是增加线程数来控制,当然内存足够大也有足够的空间来申请线程池,不过一般来讲一个进程的线程池一般会受到限制也不建议太多的,而在有限的系统资源下,要提高性能,我们开始有了new IO技术,也就是NIO技术,新版的里面又有了AIO技术,NIO只能算是异步IO,但是在中间读写过程仍然是阻塞的(也就是在真正的读写过程,但是不会去关心中途的响应),还未做到真正的异步IO,在监听connect的时候他是不需要很多线程参与的,有单独的线程去处理,连接也又传统的socket变成了selector,对于不需要进行数据处理的是无需分配线程处理的;而AIO通过了一种所谓的回调注册来完成,当然还需要OS的支持,当会掉的时候会去分配线程,目前还不是很成熟,性能最多和NIO吃平,不过随着技术发展,AIO必然会超越NIO,目前谷歌V8虚拟机引擎所驱动的node.js就是类似的模式,有关这种技术不是本文的说明重点;将上面两者结合起来就是要解决大文件,还要并行度,最土的方法是将文件每次请求的大小降低到一定程度,如8K(这个大小是经过测试后网络传输较为适宜的大小,本地读取文件并不需要这么小),如果再做深入一些,可以做一定程度的cache,将多个请求的一样的文件,cache在内存或分布式缓存中,你不用将整个文件cache在内存中,将近期使用的cache几秒左右即可,或你可以采用一些热点的算法来配合;类似迅雷下载的断点传送中(不过迅雷的网络协议不太一样),它在处理下载数据的时候未必是连续的,只要最终能合并即可,在服务器端可以反过来,谁正好需要这块的数据,就给它就可以;才用NIO后,可以支持很大的连接和并发,本地通过NIO做socket连接测试,100个终端同时请求一个线程的服务器,正常的WEB应用是第一个文件没有发送完成,第二个请求要么等待,要么超时,要么直接拒绝得不到连接,改成NIO后此时100个请求都能连接上服务器端,服务端只需要1个线程来处理数据就可以,将很多数据传递给这些连接请求资源,每次读取一部分数据传递出去,不过可以计算的是,在总体长连接传输过程中总体效率并不会提升,只是相对相应和所开销的内存得到量化控制,这就是技术的魅力,也许不要太多的算法,不过你得懂他。类似的数据处理还有很多,有些时候还会将就效率问题,比如在 HBase 的文件拆分和合并过程中,要不影响线上业务是比较难的事情,很多问题值得我们去研究场景,因为不同的场景有不同的方法去解决,但是大同小异,明白思想和方法,明白内存和体系 架构 ,明白你所面临的是沈阳的场景,只是细节上改变可以带来惊人的效果。今天开始想写一个脚本语言编译器。在这个领域,我还是知道的太少了,写的这个过程肯定是艰辛的,因为之前从来没有接触过这类的东西。写在自己的博客里,算是记录自己的学习历程吧。相信将来自己有幸再回过头来看到自己写的这个东西,一定会感觉当时的自己很有意思吧。哈哈。
首先要做的事情是先明白一些基础性的知识。分清楚几个概念。搞明白自己要做的是什么。
1、程序设计语言(Java,C,C++等)这些在设计程序时用的语言就是程序设计语言。程序写完了,就需要有相应额软件来执行。这种软件就是语言处理器。
2.语言处理器是什么?
语言处理器可以分为解释器和编译器。
解释器:解释器根据程序中的算法执行运算。他就是一种用来执行程序的软件。程序输入的同时会立即执行。执行速度较慢。
虚拟机:解释器如果执行的程序由虚拟机器语言或者类似于机器语言的语言写成,那这种软件也叫虚拟机。
编译器:编译器能将一种语言写的程序转换成另外一语言写的程序。一般就是把源程序转换成机器语言程序。(C语言用的就是编译器,直接把C程序编译成机器语言程序。C语言也提供了解释器,但是很少用,编译后的机器语言会暂时存在磁盘的某个文件中,然后借助操作系统【操作系统也是一个软件】读取机器语言的二进制文件再Copy到内存里,进而执行)
狭义的编译器会以文件的形式把编译后的程序存储在磁盘上。所以只要源程序不变,那编译就只需要一次就ok,执行时间也会缩短。(有些解释器内部的编译器不会保存转换后的程序文件)编译过程费时,执行过程较快。
编译:转换的这个动作就叫编译
源码转换器:如果编译器么有把源代码直接转换为机器语言,那这个软件就要源码转换器。
Java程序编译执行的整个流程。
第一步:Java源代码通过编译器被编译成Java二进制代码(字节码)
第二步:Java二进制代码一部分通过Java虚拟机的解释器执行,另一部分通过动态编译(JIT编译)来编译成二进制的机器语言代码。
有了一定的基础,现在就是要开始逐步设计语言了。在具体实现之前,先设计语言的基本语法。如果想要从零开始设计一种新颖实用的语言,结果往往烂尾。所以,先设计设计一下语言的简单语法,实现相应的语言处理器,一点点的完成。
功能1:四则运算
功能2:处理字符串
功能3:支持变量
功能4:一些简单的基本控制语句
阅读(...) 评论()java网络编程的一个小问题
[问题点数:20分,结帖人apple_pie]
java网络编程的一个小问题
[问题点数:20分,结帖人apple_pie]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
本帖子已过去太久远了,不再提供回复功能。共有 763 人关注过本帖
标题:一个小问题
等 级:新手上路
帖 子:233
&&问题点数:0&&回复次数:10&&&
一个小问题
实在找不到哪儿错了.大家帮帮忙了.import java.awt.*;import javax.swing.*;import java.awt.event.*;
public class RadioButtonDemo extends JFrame implements ItemListener {
private JRadioButton jrbRed,jrbYellow,jrbG
private ButtonGroup btg=new ButtonGroup();
public static void main(String args[]){
RadioButtonDemo frame = new RadioButtonDemo();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//frame.pack();
frame.setSize(250,170);
frame.setVisible(true);
public RadioButtonDemo(){
this.setTitle("RadioButton demo");
JPanel p1 = new JPanel();
p1.setSize(200,200);
p1.setLayout(new FlowLayout(FlowLayout.CENTER));
light=new Light();
light.setSize(40,90);
p1.add(light);
JPanel p2 = new JPanel();
p2.setLayout(new FlowLayout());
p2.add(jrbRed=new JRadioButton("Red",false));
p2.add(jrbYellow=new JRadioButton("Yellow",false));
p2.add(jrbGreen=new JRadioButton("Green",false));
jrbRed.setMnemonic('R');
jrbYellow.setMnemonic('Y');
jrbGreen.setMnemonic('G');
btg.add(jrbRed);
btg.add(jrbYellow);
btg.add(jrbGreen);
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(p1,BorderLayout.CENTER);
this.getContentPane().add(p2,BorderLayout.SOUTH);
jrbRed.addItemListener(this);
jrbYellow.addItemListener(this);
jrbGreen.addItemListener(this);
void itemStateChanged(ItemEvent e){
if(jrbRed.isSelected()) light.turnonRed();
if(jrbYellow.isSelected()) light.turnonYellow();
if(jrbGreen.isSelected()) light.turnonGreen();
class Light extends JPanel{
public Light(){
turnonGreen();
public void turnonRed(){
repaint();
public void turnonYellow(){
repaint();
public void turnonGreen(){
repaint();
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(10, 10, 20, 20);
g.setColor(Color.black);
g.drawOval(10, 35, 20, 20);
g.drawOval(10, 60, 20, 20);
g.drawRect(5, 5, 30, 80);
else if(yellow){
g.setColor(Color.yellow);
g.fillOval(10, 35, 20, 20);
g.setColor(Color.black);
g.drawRect(5, 5, 30, 80);
g.drawOval(10, 10,20,20);
g.drawOval(10, 60, 20, 20);
else if(green){
g.setColor(Color.green);
g.fillOval(10, 60, 20, 20);
g.setColor(Color.black);
g.drawRect(5, 5, 30, 80);
g.drawOval(10, 10, 20, 20);
g.drawOval(10, 35, 20, 20);
g.setColor(Color.black);
g.drawRect(5, 5, 30, 80);
g.drawOval(10, 10, 20, 20);
g.drawOval(10, 35, 20, 20);
g.drawOval(10, 60, 20, 20);
public Dimension getpreferredSize(){
return new Dimension(40,90);
搜索更多相关主题的帖子:
&&&&&&&&&&
等 级:贵宾
威 望:53
帖 子:4265
是编译错误么?有错误信息么?
目前兴趣所在
等 级:新手上路
帖 子:233
没有编译错误,所以找不到.
等 级:贵宾
威 望:53
帖 子:4265
那就是你程序逻辑错误呗那只有自己找了
目前兴趣所在
等 级:新手上路
帖 子:174
等 级:新手上路
帖 子:233
再次置顶,大家帮忙.
等 级:贵宾
威 望:36
帖 子:1353
应该没什么大问题,是你画的问题,色彩,填充模式等.稍微改下就好!
老牛明知夕阳晚,不用扬鞭自奋蹄;
等 级:新手上路
帖 子:98
repaint();调用的是paint方法,而你写的一大段paintComponent怎么会被调用呢?
来 自:灌水之王
等 级:友情版主
威 望:155
帖 子:28492
专家分:57
你都不说你想实现什么,这个程序会有什么异常,叫我们如何帮你排错?
可惜不是你,陪我到最后
等 级:新手上路
帖 子:58
你是不是想根据几个单选框来改变灯的颜色,好像要用线程吧
泛出微微的蓝色的光,像有生命般涌动着,闪烁着,平滑而优美,只有永恒可以于它并存
版权所有,并保留所有权利。
Powered by , Processed in 0.032596 second(s), 8 queries.
Copyright&, BCCN.NET, All Rights Reserved正常的Java程序员一般都是如何思考的?
o &nbsp,&nbsp
今天和做后台的哥们吵了一架,虽然后面逐渐歪到不知道什么地方了,但是起因相当纠结。
前端在调用后台接口时完全无响应了,于是喊后台去看错误日志。查看半天之后,是前几分钟测试关闭MongoDB会引发什么问题时,读取MongoDB获取到的Array变成了nil,使用中压根没判断是空数组还是长度为零的数组,然后后续所有使用都直接NullPointer异常了。
我相当蛋疼的吐槽这代码太特么的不“撸棒”了,于是对面程序员相当火大“每一个对象在使用时还要判断是否存在?这代码还能写吗?”
然后我真火了。我说我特么的为毛那么恶心现在前端的代码,就是恶心那一堆用前不判断用完不释放顾吃不顾拉连擦屁股都不做的傻X逻辑的。使用前判断对象是否可用不是应该做的吗?懒得到处写的话写个getter会死吗?用完释放——哦我忘了Java不需要自己管,不过我记得有dispose之类的吧?吃完饭收拾盘子,拉完X擦屁股是应该的吧?
然后说到无响应。我说你那边既然都报错了,java那么好用的try catch机制,抓住异常做个判断,是已知异常做错误处理,未知异常通知前台一个未知错误不行吗?无响应是什么鬼?然后被回答你们前端loading连个超时都没有吗?超时给个网络连接错误啊…
我心说前端有断线重连,而且明明可以立即返回响应的非要前端走超时逻辑是特么的什么个意思。和服务器是socket连接,断网断socket都有捕捉,捉不到的只能是奇葩状况了。
然后又说到我接手的时候请求已经是两套回复架构了,一套正常的回复,一套异常处理回复,异常处理只有请求码,错误码和错误消息。我说你们敢按着对应请求回复错误信息,把请求信息包含进去吗?我现在如果两条同样功能不同数据的请求,压根不知道哪条错了啊。
回曰,现在基本都是一问一答,用不着。而且后台报错是统一处理,只要throw Exception然后统一catch了发前端就行了,修改的话需要改太多地方,太麻烦。然后给我说了一堆,总之是前端只要把现在的两套回复处理自己按逻辑判断合并然后重写一遍就好。
当时我是彻底无语了,算了,前端重写就重写吧,带的那几个哥们不一定能搞定,自己写也花不了太多时间,总之等我啥时候受不了了闪人的时候让后续接手的傻X自己看着办吧。
关于伯乐小组
这里有好的话题,有启发的回复和值得信任的圈子。
新浪微博:
推荐微信号
(加好友请注明来意)
- 好的话题、有启发的回复、值得信赖的圈子
- 分享和发现有价值的内容与观点
- 为IT单身男女服务的征婚传播平台
- 优秀的工具资源导航
- 翻译传播优秀的外文文章
- 国内外的精选博客文章
- UI,网页,交互和用户体验
- 专注iOS技术分享
- 专注Android技术分享
- JavaScript, HTML5, CSS
- 专注Java技术分享
- 专注Python技术分享
& 2016 伯乐在线}

我要回帖

更多关于 java编程规范 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信