作者归档:ldsea

我今晚不晓得吃什么好。大家能不能用安妮宝贝的语式安慰。

楼主: 

如题。
如我这般,独立,凌冽的女子,难得跟一次风,不要毒药,才好。
安。

1L:酱油拌饭,适合你这般素淡的女子。一碗,足矣。

2L:红烧猪蹄,符合楼主,这般,蛋蛋地,忧桑

 

3L:我想,吃泡面,是会被遗忘的,吃煮面,却可以被记念

 

4L:薯条。茄汁。包在白色棉布裙里。下锅。甜美绚丽。

 

5L:楼主你可以穿着干净的棉布裙子,光脚穿球鞋,披散着一头海藻般浓密的长发,静静的站在厨房里,在夕阳里,慢慢的,仔细的,煮一碗,方便面。直到遇见你的那个他,理着平头,穿白色衬衣,掌心有痣。他会对楼主你说,走,我带你去吃,过桥米线……

 

6L:炸酱面吧,
  
  身边的喧嚣,
  
  与你无关

 

7L:咸菜,馒头,咀嚼的痛楚,钢刀似的滑过你的口腔。
  长发,如海藻,颤动的面孔,凛冽,而馨香

 

8L:一个不知道吃什么好的我,如何安慰一个不知道吃什么好的你。。。(串台了,这分明是琼瑶奶奶的)

 

9L:食物一个人对自我的关照和反省。
  去路边的小店吃点心吧。小馄饨,排骨年糕,牛肉粉丝汤。总有人排队等生煎馒头开锅。
  做一个清净的女子,并且吃饭。

 

10L:我想 有些猪肉 是可以红烧的
  有些番茄 是可以炒蛋的
  有时吃饭 能心甘情愿
  有时吃饭 却无能为力
  吃晚饭,这是,你的劫难 。

11L:漆黑的房,安静如她,抽空的胃,麻木的味蕾,夹在指缝中的烟,灰落满地,她望向桌上红色盒子的CHINA,寂寞就是她的食物。

 

12L:  兔是一个沉静安然的女子,她披散着海藻般的长发,湿漉漉未干,形状美好的散落。feng flower的味道氤氲暧昧。
    她脚指甲上的印度蔻丹在黑暗中熠熠。
    深夜,irc的小绿花盛开,那个叫林的男人和她约定吃晚饭。林理干净的平头,穿棉布衬衫,喜欢软壳的red river,用毛肚味道的香水。
    她未决绝,天真端倪自己的欲望,也许一道精致的鲜绿时蔬就能满足自己凛冽的胃。亦或一例散发清香的豆汁。佐………..

13L: 在你的记忆里,可曾有这样一家店?
  
  店招是凛冽的红,金色大字,刺痛过你的眼。店里有扎着随意马尾的女子,沉默、倔强、把袋子丢过来:“鸭脖子五块!”
  
  你微微一怔,嘴角弧度上扬,轻笑起来,同时不声不响付过钱走出绝味鸭脖。你想你们是同类,是漆黑中独自生长的植物,同样倔强而安静,且各自绝望的爱着这世上相同的一件事物——鸭脖子

 

14L: 妹妹肚子饿,看勤劳哥哥为你撑起一片天。。(知音体)
  呐,做人呢,吃不吃都无所谓的,最重要的是开心。呐,我去给你煮碗糖水,喝了就好了。。。(TVB体)
  爱糖水,爱砍价,
  更爱方便面。
  爱鱼香肉丝,爱糖醋排骨,
  七分熟牛排刚合适。
  我是饿人,我爱盖浇饭。。(凡客体)
  今日,肚子饥饿的楼主笑容满面的走近超市选购,看着六块钱一斤的鸡蛋,二十块钱一斤的猪肉,三块钱一斤的青菜,不禁流下了激动的泪水。
  她频频擦拭眼角泛起的泪花,面带笑容,诚恳地说道:“现在我们生活好了, 感谢国家,感谢government,我们老百姓真的是有福了……”
  围观群众纷纷鼓掌示意,人群中不时传来几声赞同……(新闻联播体)
  
   我坐在宜家的小牛皮沙发上,环顾着客厅的达芬奇家具,手中端着刚从英国飞来的红茶,细细啜饮。旁边水晶的茶座上随意摆放着刚脱下的GUCCI墨镜和 Giorgio Armani的西装外套,空气中氤氲着CHANEL NO5的气息让我仿佛置身于拎着hermes走在上海的那个年代……(四娘体)
  
  不好意思我是串台君

 

15L: 她用低沉有磁性的嗓音说:一碗牛肉面,就颓然坐在油腻和破损的桌子旁边,并仰起脸来看陌生的人。阳光倾泻的洒在黯然淡漠的脸上,寂寞的神情让她有种与众不 同的味道。她摸出了一根烟点燃了,她只抽红双喜,劣质的香烟气味和空气中飞扬的灰尘的混合在一起,很快,她吃光了一碗,起身离开的时候,她流下了一滴泪。

 

16L:柔滑如唇,猪油拌饭。

 

17L:饥饿是假象,只太过寂寞。兔这样寂寞的女子,光脚坐在阳台上的CD中间。她只穿素的棉和亚麻,倾心于衣服上每一道原色的褶皱。一杯不加糖的咖啡。苦。涩。浸过喉咙瞬间的甜。胃部有些许的温暖感,滟酽的咖啡香。
  兔是如此特立独行的女子。自然。清新。寂寞。
  晚饭只是一杯咖啡。苦的。

 

18L:像我这样的女人,总是以一个难题的形式出现在感情里。
  今晚,这样的夜
  究竟是夹饼?还是肉夹馍
  我的世界是寂静无声的,容纳不下别人。
  选择
  是如此的明媚忧伤

19L:我。从未发现。世界上。有像安妮宝贝。一样的。奇葩。

 

20L:光脚坐在地板上 夏末的夜依然有些微凉 我听着Legend of phoenix的《Above the moon》。 激越的音乐 ,却又带着奇怪的古老感, 划过黑夜的空气。
  门铃响了 ,我走到门口 。是,送外卖的男子。
  白色却有些污痕的制服,脸上尽是青春的痕迹,他,今年不过十六七岁吧。门口微弱的白灯下,我与他,两双黑漆漆的眼睛对望着
  “炒牛河,15块。”
  我拿钱给他,微笑地轻声说道:“谢谢”
  这时他却突然一怔,不言语地低头匆匆走了
  少年的羞涩,重叠了记忆中校门口那个已远去的背影。猛然,一阵剧烈的抽痛抓紧了我的心脏,我,赫然发现,他还没把炒牛河给我

21L:盛夏的尾巴的风。鼓楼斑红的城墙。一个温和而萧飒的男子,霜染白发,带着大洋彼岸的风的气息。与一个明眸善睐的年轻姑娘。6元一碗的炸酱面。
  
  
   答案: 姚记炒肝 炸酱面 涨价啦!!!

 

22L:在水里。漂浮的。海藻般的。煮。蔬菜。蘸上。细滑浓郁的。麻酱。
  一如楼主。这朵。忧郁的。安静的。女子。
  
  额……好像是银镯体?不管了。

 

23L:兔是我的妻,我叫春树。
    。。。。。。。。。。。。。。。。。。
    9月初的一个夜晚,妻兔子和以往一样的时间回家。
    她在玄关脱下夏诺瓦路的高跟鞋,语气平淡的说:"万分对不起,今天就是没有心情做饭。"
    "请务必对此感到抱歉。"我说,"大可喝一晚上的凉水。"……

24L:是不想吃晚饭。如果有一盘菜值得深爱,为它吃撑了也是幸福的。只是没有那样一盘菜。

 

25L:“小栓进来罢!”华大妈叫小栓进了里面的屋子,中间放好一条凳,小栓坐了。他的母亲端过一碟乌黑的圆东西,轻轻说:
  “吃下去罢,——病便好了。”
  小栓撮起这黑东西,看了一会,似乎拿着自己的性命一般,心里说不出的奇怪。十分小心的拗开了,焦皮里面窜出一道白气,白气散了,是两半个白面的馒头。— —不多工夫,已经全在肚里了,却全忘了什么味;面前只剩下一张空盘。(你让鲁迅先生情何以堪啊)

 

26L:他带她去吃牛肉面
  
  在肮脏油腻的小店
  
  她笑容凛冽 看着对面这个素净的男子 她知道这就是安心
  
  他忽然嘟囔了一句:MLGB 肉 放的越来越少了

 

27L:西。北。风。饮之~~~

28L:我觉得我应该按照自己最初的决定,去煮一碗广式糖水,看着糖水里柔软透明的胶状物,我的笑容会像阳光一样纯粹,我清澈的眼神会像雪山一样遥远。
    
    然后,我可以一个人坐在窗台边的地板上,看樱花树在风中摆动。黄昏的雨天,在空荡荡的房间里拉小提琴。用帕格尼尼的两根弦,谋杀掉我的思想和感情。
    
    可以在一个小城市里,一直这样平静地生活下去。
    
    我要嫁给那个高大英俊的男人。他的睫毛就像华丽而伤感的威尼斯。我们曾经相爱。我要在他的身边,不离开他。告诉他,我愿意和他相守到老。
    
    可是,我们最终没能在一起。
    
    因为,他喜欢泡面。他喜欢光着脚坐在大藤椅上,一杯泡得浓黑的咖啡,红双喜的特醇香烟,和一碗康师傅红烧牛肉面。
    
    糖水和泡面,如同马德里乡间的一朵雏菊,得不到爱琴海深处海藻的爱情。
    
    糖水有什么不好?我的唇边绽开一抹嘲讽的笑。那,做人呢,最重要就是开心

 

29L:十六号,四月十六号。二零一一年四月十六号下午三点之前的一分钟你和我在一起,因为你我会记住这一分钟。从现在开始我们就是一分钟的朋友,这是事实,你改变不了,因为已经过去了。我明天会再来。
  
  “猪耳朵加不加辣椒?打不打包?”

 

30L:兔君啊~~
  你是不是饿呀滴慌~~呀呼咿呀嘿~
  如果你是饿滴慌
  请你对我十娘讲~
  十娘我给你做面汤~~~
  【以上边唱边跳,请自行想象……】
  

一下内容源自人人网:

孔筱熙西红柿炒蛋,酸涩的,却能让我颤抖。

王小若清澈澄净的一锅水,打一个荷包蛋。翻滚,沸腾。那雾气在她的深邃眼睛中融化开来。她不禁低下头抱住自己,海藻一般乌黑浓密的长发遮挡住她苍白的脸颊。她抑或是在等待着,一个有着清澈眼神,穿棉布衬衫的安静男子来救赎她。 我也来排队哈哈。

肖群操: 她望着掉在棉布裙子上的红烧肉,想起了那个穿棉布衬衫,目光清澈、笑容素雅的男子。周围的喧嚣声与她无关,夕阳的光线投在她沉静的侧脸上。她的嘴角弧度上扬,淡淡的微笑:愿现世安稳,岁月静好。

李瑞雪 店里有扎着随意马尾的女子,沉默、倔强、把袋子丢过来:“鸭脖子五块!”

王二不小 他 还是没能忘记那个午后淡然的阳光,透过门缝倾在地上,抚摸着他蹲在地上的孤独。无论怎样,还说要伸手出去抓呀。触手可及,小虫纷纷飞舞,一片氤氲。他闭 上眼睛,安享那份恬淡。转而抓起一些来吃,眼中竟只是碳水化合物而已,冰冷,孤寂。他忽然感到胃里一阵痉挛,像悲伤抽打着心灵,终于呕吐出来。屎,究竟不 是普通男子可以吃的。

李超 吃鱼吧。那些美丽的小鱼,它们睡觉的时候也睁着眼睛。不需要爱情,亦从不哭泣。它们是我的榜样。

郭士亮 那 个男人,指尖留着淡淡的烟味,面容里布满了岁月过隙的忧伤,我就这么沉醉于其中,刹那间,于是,片刻就演变成了永远,永远却逃不离生命的索求。欲望,燃 烧在彼此中间,我就那么期盼着,期盼着,宛如饥肠辘辘的女人在期盼红烧肉般期盼着他的停留,片刻亦好,只愿他不要让我的期盼就这么在风雨中飘摇,孑然而 立。

刘珺如 好吧,我也來搗亂…哈哈. 
她俯在陽台的欄杆上,看這個城市的疆界模糊在霓虹閃爍中.世間紛擾,往來洶湧,跌宕籬亂.因著植物般的格局,天地喜樂,自在心間,一杯清水,亦是歡喜.

Wireshark “The NPF driver isn’t running…”

前几天重装系统,装上了windows7 RC系统。昨天开始尝试装上了wireshark 这款很强大的网络监视软件,满心欢喜的打开,可是每次打开都会弹出“The NPF driver isn't running…”的错误提示窗口。昨天晚上折腾了一晚上也没有解决。百度和谷歌了一番都说要打开 NPF driver ,然后我找到了C:\\Windows\System32\Drivers\下的npf.sys文件,可是这个文件怎么启动呢?我还真不知道。

来到公司,本来已经打算放弃了,没想到今天在同事的帮助下解决了。这里写出来,给需要的兄弟们分享下:

首先,你得确认自己安装了winpcap(最好下载一个最新版本:官方下载,这会官方好像打不开,也可以华军下载),然后

(1)如果你使用的是Linux、Ubuntu系统,请用 >$ su Administrator命令切换到拥有最高权限的帐号,然后再输入命令:“net start npf”(如果不行自己查找类似命令)。

(2)如果使用的是windows xp\me,请使用管理员帐号登录,然后打开cmd,输入命令:“net start npf”,会提示打开驱动服务成功。

(3)如果使用的是Windows vista或者跟我一样试用的Windows 7,请找到“C:\Windows\System32”下的 cmd.exe 文件,右键点击选择“Run as administrator”,然后在命令行模式下输入命令“net start npf”,即可成功打开NPF的驱动,应该就是我前面找到过的 npf.sys 文件被打开了。

最后,再重新打开Wireshark, "bingo" 终于能正常运行了。

矫情一把,转一篇

【1】小时候,我安静坐在教室做习题,她偏要我偷看窗外,隔壁班男生的脸。大学毕业,我四顾茫然,她鼓动我远走他乡,去追梦。失恋夜,我欲飞下高 楼,她拼命拉住我,骂我没出息。儿子出生那天,她陪着我笑,笑中带泪。这些年,我恨她,也爱她,她是住在我身体里的另一个自己,我们是双生的花。

 

【2】 黑人司机载了一对白人母子,儿孩问:“为什么司机伯伯的肤色和我们不同?”母亲答:“上帝为了让世界缤纷,创造了不同颜色的人。”到目的地黑人司机坚持不 收钱,他说:“小时曾问过母亲同样问题,母亲说我们是黑人,注定低人一等,如果她换成你的回答,今天我定会有不同的成就。

 

【3】 他寒门学子,她富家千金。他鼓足勇气给她写情书:我爱你,但是……她回信,也是五字:……但是,我爱你。他们喜结连理。婚后,一场大火从天而降。他安然无 恙,她却再不敢照镜子。她留下遗书也是最后一封情书:我爱你,但是……他幸早发现!她医院醒过来,床头有一张纸:……但是,我爱你

 

【4】 电视厨艺比赛,他身为评委端居高位.主持人采访他"请问您吃过最美味的菜是哪一道?"他冲着镜头诡秘一笑,"那年大三,晚上饿得要死的时候,我老婆居然为 我偷偷煮了一碗泡面,那是我人生中最美的一餐~"电视前的某人捏着筷子咬牙切齿,"呸!明明是半夜溜回寝室抢了我的晚饭!"

 

【5】 她很胖,以致于医生和她说过,如果不减肥,以后结婚别想有孩子。因为这样,她一直没答应他的求婚,每次他问为什么的时候,她都沉默,直到有一天她眼泪决 堤,告诉他,有可能一辈子没有宝宝,这样为什么还要在一起,他笑着说“我早就知道了,傻丫头,没有就没有,你就是我的宝宝啊!

 

【6】他接到他的电话,喜欢了七年的他。他对他说:我们在一起吧。尽管已经听到电话那头的别人的窃窃笑声,他还是淡定的说:好啊。然后他说:大冒险又输了吧?他说:其实我选的是真心话。

 

【7】 毕业典礼上,他突然凑到她耳边幽幽地说了声:“我喜欢你。”她笑“喂,调戏了我三年,够了吧。”三年来,隐藏起自己的感情来面对自己暗恋对象一次又一次的 挑逗,她真的已经很累了。“我说真的!”他看她不信,又严肃地说了一次。“你哪次不是说真的。”他低头:“其实,哪次都是真的。"

 

【8】 她花了一周的晚上给他织好了这条围巾,从小娇生惯养,这是她的第一条围巾,她幻想着他惊喜的表情。在他生日的那个晚上,她刚幸福地把围巾给他围上,他却厌 倦地取了下来“我不喜欢围巾"!心,瞬间冰凉!爸爸来了,以为是给自己的,自顾地围上,满脸都是幸福的笑容。她转过身来,泪流满面…

 

【9】 旅人来到一个叫“谎话国”的地方,他问一个国人:为什么这里叫谎话国?国人:因为皇帝的新装就发生在我们国家,我们所有人都说谎骗了国王。旅人:可我记得 有个孩子说了真话啊。国人:那个孩子被送进了精神病院,直到他学会说谎才被放出来。旅人:你怎么知道的?国人:因为我就是那个孩子。

 

【10】 她知道他的父皇灭了她的国家,嫁给他是为了复国的计划,现在她成功了,她看着士兵包围了他,而他的剑正横在她的颈项,她闭上眼平静的等待死亡,却听见耳边 他的说话:下辈子,没有国,只有家。他猛的推开她,无数羽箭穿透他的胸膛。她抱着他离开了这个国,青灯佛前,只为许一个来世的家。

 

【11】 他三十岁不到便开始脱发,她笑着摸摸他的头捉狭他:我看你的头型挺好看啊!就是掉光了头发也不怕!他皱眉:我接受不了自己秃头的样子。她三十岁那年,他突 然剃光了头,笑嘻嘻地问她好看不,摸摸她的头问她要不要跟他来个情侣装。她笑了,眼眶却湿了。那是她接受化疗的第一天。

 

【12】 弟子问师傅:“您能说说人类的奇怪之处吗?”答:“他们急于成长,然后又哀叹失去的童年;他们以健康换取金钱,不久后又想用金钱恢复健康。他们对未来焦虑 不已,却又无视现在的幸福。因此,他们既不活在当下,也不活在未来。他们活着仿佛从来不会死亡;临死前,又仿佛他们从未活过。” 

 

【13】 相亲会上,父亲说“我女儿又漂亮,又会做饭”她摸摸脸上的疤痕,心想我哪里会做饭了?交往渐渐频繁,她问他,以前有喜欢的人吗?“有,她漂亮,会做饭”她 开始学料理,每次他吃了,总会说,“味道真像。”后来,她终于生气。“你爱我还是爱她!”他笑,“傻瓜,她车祸失忆后,我一直在等她”

 

【14】 十年来,她努力学大提琴,却没有任何进步。母亲为此而不停苛责她,巨大压力下,她一狠心自毁双目,却意外地在黑暗中找回了失落的才华。首场个人音乐很成 功,站在舞台上的她笑着聆听掌声,殊不知,观众席上只有一位满脸悔恨的母亲,正高举着录音笔并反复按下播放键,无声流泪。

 

【15】 儿子养不起年迈的母亲,决定把她背上山丢下去。傍晚,儿子说要背母亲上山走走,母亲吃力地爬上他的背。他一路都在想爬高点再丢下她,当看到母亲在他背上偷 偷往路上洒豆子,他很生气地问:“你洒豆子干什么?”结果母亲的回答让他泪流满面:“傻儿子,我怕你等会儿一个人下山会迷路。

 

【16】 她被男朋友甩了,一场瓢泼大雨浇下,像一根根冰魄银针,够凉够狠够绝情。四年的感情过不了毕业这道坎,说好要一起直到白发苍苍,只因他进了500强,她却 处处碰壁,成了累赘。又一个四年,他还是企业里的小职员,她却笑傲商场成了广告女王。倘若失去了心,每秒皆是地狱,只有涅槃,方能重生。

 

【17】 爸爸:儿子你觉得爸爸壮吗?儿子:嗯。爸爸:你觉得少林功夫厉害吗?儿子:厉害。爸爸:如果我剃成光头,练少林功夫好吗?儿子拍手:太好了。第二天,儿子 看到光头的爸爸,高兴地说:爸爸加油,一定要练成高手。那天,是爸爸化疗的前一天。那天,爸爸用特有的方式教会了儿子乐观和勇敢

 

【18】 相愛多年,他常带着她四处游玩。遇到人多的地方,他总说:“要是走散了,就留在原地等我,我一定会回来找你。” 这一天她又与他走散了,但她在原地等了很久,却一直等不到他回来…… 一个深夜里,有个中年男子找来,握住她的手柔声说:“妈,爸已经过世很多年了,您别在等他了。”

 

【19】著名预言家被自己 心爱的女人杀死,在临死前,那女人得意的说:“什么预言家,你算得出全世界,却算不了自己的命。”预言家却无比凄凉的笑道:“在见到你的那一刻,我就已经 知道这结局,只是在那一瞬间,我决定原谅你。”——原来,大家都这样:逃得开的是命运,逃不开的是选择。

 

【20】小时候事故的关系,妹妹只能记得三个人——父母和我。在她16岁生日那天,我对她说:“如果你有了喜欢的人,就把我忘了、将那个人记在心里吧。” “我才不会呢”,妹妹笑了。 第二年的某一天,妹妹和她的男友一起找到我,她带着哭腔对我说:“哥哥,我是谁啊?”

使用chkdsk工具修复移动硬盘方法详解

chkdsk

  

chkdsk的全称是checkdisk,就是磁盘检查的意思,你无法也不必使用该文件,这个东西是当你的系统当掉或者非法关机的时候由系统来调用检查磁 盘的。基于所用的文件系统,创建和显示磁盘的状态报告。Chkdsk 还会列出并纠正磁盘上的错误。如果不带任何参数,chkdsk 将显示当前驱动器中的磁盘状态。

 

  语法

 

  chkdsk [volume:][[Path] FileName] [/f] [/v] [/r] [/x] [/c] [/l[:size]]

 

  参数

 

  volume:

 

  指定驱动器号(冒号分隔)、装入点或卷名。

 

  [Path} FileName]

 

  指定需要 chkdsk 检查碎片整理的文件或文件集的位置和名称。使用通配符(* 和 ?)可以指定多个文件。

 

  /f

 

  修复磁盘上的错误。必须锁定磁盘。如果 chkdsk 无法锁定驱动器,则会显示一条消息,询问您是否希望在下次重新启动计算机时检查该驱动器。

 

  /v

 

  当检查磁盘时,显示所有目录中每个文件的名称。

 

  /r

 

  找到坏扇区并恢复可读取的信息。必须锁定磁盘。

 

  /x

 

  仅在 NTFS 上使用。如果必要,首先强制卸载卷。该驱动器的所有打开句柄都无效。/x 还包含了/f 的功能。

 

  /i

 

  仅随 NTFS 使用。对索引项执行充分检查,降低运行 chkdsk 的所用时间量。

 

  /c

 

  仅随 NTFS 使用。跳过文件夹结构中的周期检查,减少运行 chkdsk 所需的时间量。

 

  /l[:size]

 

  仅随 NTFS 使用。将日志文件的大小更改为由用户输入的大小。如果省略该参数,则 /l 会显示当前日志文件的大小。

 

  /?

 

  在命令提示符显示帮助。

 

  注释

 

  运行 chkdsk

 

  要在固定磁盘上运行 chkdsk 命令,您必须是该 Administrators 组的成员。

 

  重新启动时检查锁定的驱动器

 

  如果希望 chkdsk 修复磁盘错误,则此前不能打开该驱动器上的文件。如果有文件打开,会显示下述错误消息:

 

  Chkdsk cannot run because the volume is in use by another processWould you like to schedule this volume to be checked the next time the system restarts?(Y/N)

 

  如果选择下次重新启动计算机时检查该驱动器,则重新启动计算机后 chkdsk 会自动检查该驱动器并修复错误。如果该驱动器分区为启动分区,则 chkdsk 在检查完该驱动器后会自动重新启动计算机。

 

  报告磁盘错误

 

  chkdsk 命令会检查磁盘空间和文件分配表 (FAT)以及 NTFS 文件系统的使用情况。Chkdsk 在状态报告中提供特定于每个文件系统的信息。状态报告显示文件系统中找到的错误。在活动分区上运行 chkdsk 时,如果未含 /f 命令行选项,则它可能会因为无法锁定该驱动器而报告虚假信息。应该不定期使用 chkdsk 检查每个磁盘上的错误。

 

  修复磁盘错误

 

  只有指定 /f 命令行选项,chkdsk 命令才修复磁盘错误。Chkdsk 必须可以锁定驱动器以纠正错误。由于修复通常会更改磁盘的文件分配表,有时还会丢失数据,所以 chkdsk 会首先发送如下所示的确认消息:

 

  10 lost allocation units found in 3 chains.

 

  Convert lost chains to files?

 

  如果按 Y,Windows 会在根目录中将所有丢失链保存在一个名为 Filennnn.chk 的文件中。chkdsk 结束后,可以查看这些文件是否包含了所需的数据。如果按 N,Windows 会修复磁盘,但对于丢失的分配单元,它不保存其内容。

 

  如果不使用 /f 命令行选项,则在有文件需要修复时,chkdsk 会发送消息,但它不修复任何错误。

 

  如果在大磁盘(例如,70 GB)或有大量文件(数百万)的磁盘上使用 chkdsk /f,这可能要花很长时间(比如说,数天)才能完成。因为 chkdsk 直到工作完成它才会交出控制权,所以计算机在这段时间内将不可用。

 

  检查 FAT 磁盘

 

  Windows 以下列格式显示 FAT 磁盘的 chkdsk 状态报告:

 

  检查 NTFS 磁盘

 

  Windows 以下列格式显示 NTFS 磁盘的 chkdsk 状态报告:

 

  存在打开文件的情况下使用 chkdsk

 

  如果该驱动器上有打开的文件,则指定 /f 命令行选项后,chkdsk 会发送错误消息。如果未指定 /f 命令行选项并且存在打开的文件,则 chkdsk 会报告磁盘上丢失的分配单元。如果打开的文件没有记录在文件分配表时,可能会发生这种情况。如果 chkdsk 报告大量分配单元丢失,可以考虑修复该磁盘。

 

  查找物理磁盘错误

 

  使用 /r 命令行选项可查找文件系统中的物理磁盘错误。有关使用 recover 修复物理性损坏文件的信息,请参阅“”。

 

  报告磁盘坏扇区

 

  在磁盘第一次准备运行时,chkdsk 报告的坏扇区标记为损坏。它们不会造成危险。

 

  了解退出码

 

  下表列出了 chkdsk 完成任务后报告的退出码。

 

  退出码 说明

 

  0 没有发现错误。

 

  1 错误已找到并修复。

 

  2 已执行清理磁盘(例如碎片收集),或者因为没有指定 /f 而未执行清理磁盘。

 

  3 由于未指定 /f 选项,无法检查磁盘,错误不能修复或错误未修复。

 

  故障恢复控制台提供了带有不同参数的 chkdsk 命令。

 

  范例

 

  如果要检查驱动器 D 中的磁盘,并且希望 Windows 修复错误,请键入:

 

  chkdsk d:/f

 

  如果遇到错误,chkdsk 会暂停并显示消息。Chkdsk 完成任务时会显示列有磁盘状态的报告。除非 chkdsk 已完成任务,否则无法打开指定驱动器上的任何文件。

 

  在 FAT 磁盘上,要检查当前目录中所有文件的不相邻块,请键入:

 

  chkdsk *.*

 

  Chkdsk 显示状态报告,然后列出符合具有不相邻块条件的文件。

 

  XOX

 

  使用CHKDSK命令的注意事项

 

  (1)系统存在打开的文件时

 

  当有文件打开时请不要使用CHKDSK。因为CHKDSK是假定磁盘文件处于关闭状态而设计的。当有文件打开时,相应的MS-DOS将会修改文件分配 表和目录结构。这种改变并不一定立即进行,文件分配表和目录结构的改变发生在不同时刻。因此如果磁盘上文件打开时运行CHKDSK,就会把目录结构和文件 分配表的不一致解释为出错,从而导致数据丢失或文件系统的破坏。因此,在运行其它程序,如Microsoft Windows时,千万不要运行CHKDSK。

 

  (2)CHKDSK不能用于分配的驱动器和网络。

 

  CHKDSK不能用于由SUBST命令形成的驱动器工作,也不能用于网络驱动器上的磁盘检查。

 

  (3)物理磁盘错误

 

  CHKDSK命令只能找到文件系统中的逻辑错误,而不能查找物理磁盘错误。要查找物理磁盘错误,请使用SCANDISK程序。

 

  (4)坏磁盘扇区

 

  CHKDSK报告中将坏扇区标记上“bad”,SCANDISK和其它物理磁盘错误修正程序也将坏扇区标记为“bad”,因此坏扇区不会造成危害。

 

  (5)交叉链接的文件

 

  如果有两个文件或目录共用同一磁盘空间的记录,CHKDSK会报告有交叉链接文件。如果CHKDSK发现有交叉链接文件存在,会显示类似如下信息:

 

  is cross linked on allocation unit

 

  CHKDSK不会修补交叉链接文件,即使指定了/F项。要修复交叉链接文件,需要运行SCANDISK程序,或者进行手工修复,然后复制到指定的文件中并删除原文件。

Eclipse 3.8 M1发布,支持Java 7

Eclipse基金会发布了Eclipse 3.8 M1版,这是第一个支持Java 7的里程碑版本。
 

该版本的改进包括:
 

  • 代码自动提示支持Diamond operators。
  • 移除多余的类型文字,并使用diamond operator代替
  • Content assist can be used to insert types into diamonds
  • Multi-catch can be extended with a "Surround with try/multi-catch", complementing the existing "Surround with try/catch"
  • Multi-catch can be extended with new exception types
  • Exception blocks can be combined into a single multi-catch block
  • Resources closed with try-with-resources can detect thrown exceptions and add to (multi-) catch blocks
  • Strings-in-switch 语句能够被转换到嵌套的 if/else 语句中
  • The Java7 execution environment has been added for dependency on execution environments

该版本针对Java 7的详细改进信息http://www.eclipse.org/jdt/ui/r3_8/Java7news/whats-new-java-7.html

下载地址http://download.eclipse.org/eclipse/downloads/drops/S-3.8M1-201108031800/

使用 dom4j 解析 XML

dom4j API 包含一个解析 XML 文档的工具。本文中将使用这个解析器创建一个示例 XML 文档。清单 1 显示了这个示例 XML 文档,catalog.xml。

清单 1. 示例 XML 文档(catalog.xml)

 

<?xml version="1.0" encoding="UTF-8"?> 
<catalog> 
<!--An XML Catalog--> 
<?target instruction?>
  <journal title="XML Zone" 
                  publisher="IBM developerWorks"> 
<article level="Intermediate" date="December-2001">
 <title>Java configuration with XML Schema</title> 
 <author> 
     <firstname>Marcello</firstname> 
     <lastname>Vitaletti</lastname> 
 </author>
  </article>
  </journal> 
</catalog>

 

然后使用同一个解析器修改 catalog.xml,清单 2 是修改后的 XML 文档,catalog-modified.xml。

清单 2. 修改后的 XML 文档(catalog-modified.xml)

 

<?xml version="1.0" encoding="UTF-8"?> 
<catalog> 
<!--An XML catalog--> 
<?target instruction?>
  <journal title="XML Zone"
                   publisher="IBM developerWorks"> 
<article level="Introductory" date="October-2002">
 <title>Create flexible and extensible XML schemas</title> 
 <author> 
     <firstname>Ayesha</firstname> 
     <lastname>Malik</lastname> 
 </author> 
  </article>
  </journal> 
</catalog>

 

与 W3C DOM API 相比,使用 dom4j 所包含的解析器的好处是 dom4j 拥有本地的 XPath 支持。DOM 解析器不支持使用 XPath 选择节点。

本文包括以下几个部分:

  • 预先设置
  • 创建文档
  • 修改文档

预先设置

这个解析器可以从 http://dom4j.org 获取。通过设置使 dom4j-1.4/dom4j-full.jar 能够在 classpath 中访问,该文件中包括 dom4j 类、XPath 引擎以及 SAX 和 DOM 接口。如果已经使用了 JAXP 解析器中包含的 SAX 和 DOM 接口,向 classpath 中增加 dom4j-1.4/dom4j.jardom4j.jar 包括 dom4j 类和 XPath 引擎,但是不含 SAX 与 DOM 接口。

创建文档

本节讨论使用 dom4j API 创建 XML 文档的过程,并创建示例 XML 文档 catalog.xml。

使用 import 语句导入 dom4j API 类:

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

 

使用 DocumentHelper 类创建一个文档实例。 DocumentHelper 是生成 XML 文档节点的 dom4j API 工厂类。

 Document document = DocumentHelper.createDocument();

 

使用 addElement() 方法创建根元素 catalog addElement() 用于向 XML 文档中增加元素。

Element catalogElement = document.addElement("catalog");

 

catalog 元素中使用 addComment() 方法添加注释“An XML catalog”。

 catalogElement.addComment("An XML catalog");

 

catalog 元素中使用 addProcessingInstruction() 方法增加一个处理指令。

catalogElement.addProcessingInstruction("target","text");

 

catalog 元素中使用 addElement() 方法增加 journal 元素。

Element journalElement =  catalogElement.addElement("journal");

 

使用 addAttribute() 方法向 journal 元素添加 titlepublisher 属性。

journalElement.addAttribute("title", "XML Zone");
         journalElement.addAttribute("publisher", "IBM developerWorks");

 

article 元素中添加 journal 元素。

Element articleElement=journalElement.addElement("article");

 

article 元素增加 leveldate 属性。

articleElement.addAttribute("level", "Intermediate");
      articleElement.addAttribute("date", "December-2001");

 

article 元素中增加 title 元素。

Element titleElement=articleElement.addElement("title");

 

使用 setText() 方法设置 article 元素的文本。

titleElement.setText("Java configuration with XML Schema");

 

article 元素中增加 author 元素。

Element authorElement=articleElement.addElement("author");

 

author 元素中增加 firstname 元素并设置该元素的文本。

Element  firstNameElement=authorElement.addElement("firstname");
     firstNameElement.setText("Marcello");

 

author 元素中增加 lastname 元素并设置该元素的文本。

Element lastNameElement=authorElement.addElement("lastname");
     lastNameElement.setText("Vitaletti");

 

可以使用 addDocType() 方法添加文档类型说明。

document.addDocType("catalog", null,"file://c:/Dtds/catalog.dtd");

 

这样就向 XML 文档中增加文档类型说明:

<!DOCTYPE catalog SYSTEM "file://c:/Dtds/catalog.dtd">

 

如果文档要使用文档类型定义(DTD)文档验证则必须有 Doctype。

XML 声明 <?xml version="1.0" encoding="UTF-8"?> 自动添加到 XML 文档中。

清单 3 所示的例子程序 XmlDom4J.java 用于创建 XML 文档 catalog.xml。

清单 3. 生成 XML 文档 catalog.xml 的程序(XmlDom4J.java)

 

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;
import java.io.*;
public class XmlDom4J{
public void generateDocument(){
Document document = DocumentHelper.createDocument();
     Element catalogElement = document.addElement("catalog");
     catalogElement.addComment("An XML Catalog");
     catalogElement.addProcessingInstruction("target","text");
     Element journalElement =  catalogElement.addElement("journal");
     journalElement.addAttribute("title", "XML Zone");
     journalElement.addAttribute("publisher", "IBM developerWorks");
     Element articleElement=journalElement.addElement("article");
     articleElement.addAttribute("level", "Intermediate");
     articleElement.addAttribute("date", "December-2001");
     Element  titleElement=articleElement.addElement("title");
     titleElement.setText("Java configuration with XML Schema");
     Element authorElement=articleElement.addElement("author");
     Element  firstNameElement=authorElement.addElement("firstname");
     firstNameElement.setText("Marcello");
     Element lastNameElement=authorElement.addElement("lastname");
     lastNameElement.setText("Vitaletti");
     document.addDocType("catalog",
                           null,"file://c:/Dtds/catalog.dtd");
    try{
    XMLWriter output = new XMLWriter(
            new FileWriter( new File("c:/catalog/catalog.xml") ));
        output.write( document );
        output.close();
        }
     catch(IOException e){System.out.println(e.getMessage());}
}
public static void main(String[] argv){
XmlDom4J dom4j=new XmlDom4J();
dom4j.generateDocument();
}}

 

这一节讨论了创建 XML 文档的过程,下一节将介绍使用 dom4j API 修改这里创建的 XML 文档。

修改文档

这一节说明如何使用 dom4j API 修改示例 XML 文档 catalog.xml。

使用 SAXReader 解析 XML 文档 catalog.xml:

SAXReader saxReader = new SAXReader();
 Document document = saxReader.read(inputXml);

 

SAXReader 包含在 org.dom4j.io 包中。

inputXml 是从 c:/catalog/catalog.xml 创建的 java.io.File。使用 XPath 表达式从 article 元素中获得 level 节点列表。如果 level 属性值是“Intermediate”则改为“Introductory”。

List list = document.selectNodes("//article/@level" );
      Iterator iter=list.iterator();
        while(iter.hasNext()){
            Attribute attribute=(Attribute)iter.next();
               if(attribute.getValue().equals("Intermediate"))
               attribute.setValue("Introductory"); 
       }

 

获取 article 元素列表,从 article 元素中的 title 元素得到一个迭代器,并修改 title 元素的文本。

list = document.selectNodes("//article" );
     iter=list.iterator();
   while(iter.hasNext()){
       Element element=(Element)iter.next();
      Iterator iterator=element.elementIterator("title");
   while(iterator.hasNext()){
   Element titleElement=(Element)iterator.next();
   if(titleElement.getText().equals("Java configuration with XML Schema"))
     titleElement.setText("Create flexible and extensible XML schema");
    }}

 

通过和 title 元素类似的过程修改 author 元素。

清单 4 所示的示例程序 Dom4JParser.java 用于把 catalog.xml 文档修改成 catalog-modified.xml 文档。

清单 4. 用于修改 catalog.xml 的程序(Dom4Jparser.java)

 

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Attribute;
import java.util.List;
import java.util.Iterator;
import org.dom4j.io.XMLWriter;
import java.io.*;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader; 
public class Dom4JParser{
 public void modifyDocument(File inputXml){
  try{
   SAXReader saxReader = new SAXReader();
   Document document = saxReader.read(inputXml);
   List list = document.selectNodes("//article/@level" );
   Iterator iter=list.iterator();
   while(iter.hasNext()){
    Attribute attribute=(Attribute)iter.next();
    if(attribute.getValue().equals("Intermediate"))
      attribute.setValue("Introductory"); 
       }
   
   list = document.selectNodes("//article/@date" );
   iter=list.iterator();
   while(iter.hasNext()){
    Attribute attribute=(Attribute)iter.next();
    if(attribute.getValue().equals("December-2001"))
      attribute.setValue("October-2002");
       }
   list = document.selectNodes("//article" );
   iter=list.iterator();
   while(iter.hasNext()){
    Element element=(Element)iter.next();
    Iterator iterator=element.elementIterator("title");
      while(iterator.hasNext()){
        Element titleElement=(Element)iterator.next();
        if(titleElement.getText().equals("Java configuration with XML
      Schema"))
        titleElement.setText("Create flexible and extensible XML schema");
                                          }
                                }
    list = document.selectNodes("//article/author" );
    iter=list.iterator();
     while(iter.hasNext()){
     Element element=(Element)iter.next();
     Iterator iterator=element.elementIterator("firstname");
     while(iterator.hasNext()){
      Element firstNameElement=(Element)iterator.next();
      if(firstNameElement.getText().equals("Marcello"))
      firstNameElement.setText("Ayesha");
                                     }
                              }
    list = document.selectNodes("//article/author" );
    iter=list.iterator();
     while(iter.hasNext()){
      Element element=(Element)iter.next();
      Iterator iterator=element.elementIterator("lastname");
     while(iterator.hasNext()){
      Element lastNameElement=(Element)iterator.next();
      if(lastNameElement.getText().equals("Vitaletti"))
      lastNameElement.setText("Malik");
                                  }
                               }
     XMLWriter output = new XMLWriter(
      new FileWriter( new File("c:/catalog/catalog-modified.xml") ));
     output.write( document );
     output.close();
   }
 
  catch(DocumentException e)
                 {
                  System.out.println(e.getMessage());
                            }
  catch(IOException e){
                       System.out.println(e.getMessage());
                    }
 }
 public static void main(String[] argv){
  Dom4JParser dom4jParser=new Dom4JParser();
  dom4jParser.modifyDocument(new File("c:/catalog/catalog.xml"));
                                        }
   }

 

这一节说明了如何使用 dom4j 中的解析器修改示例 XML 文档。这个解析器不使用 DTD 或者模式验证 XML 文档。如果 XML 文档需要验证,可以解释用 dom4j 与 JAXP SAX 解析器。

结束语

包含在 dom4j 中的解析器是一种用于解析 XML 文档的非验证性工具,可以与JAXP、Crimson 或 Xerces 集成。本文说明了如何使用该解析器创建和修改 XML 文档。

 

参考资料

Java线程:新特征-障碍器

Java线程:新特征-障碍器
 
Java5中,添加了障碍器类,为了适应一种新的设计需求,比如一个大型的任务,常常需要分配好多子任务去执行,只有当所有子任务都执行完成时候,才能执行主任务,这时候,就可以选择障碍器了。
 
障碍器是多线程并发控制的一种手段,用法很简单。下面给个例子:
 
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
* Java线程:新特征-障碍器
*
* @author leizhimin 2009-11-6 10:50:10
*/

public class Test {
        public static void main(String[] args) {
                //创建障碍器,并设置MainTask为所有定数量的线程都达到障碍点时候所要执行的任务(Runnable)
                CyclicBarrier cb = new CyclicBarrier(7, new MainTask());
                new SubTask("A", cb).start();
                new SubTask("B", cb).start();
                new SubTask("C", cb).start();
                new SubTask("D", cb).start();
                new SubTask("E", cb).start();
                new SubTask("F", cb).start();
                new SubTask("G", cb).start();
        }
}

/**
* 主任务
*/

class MainTask implements Runnable {
        public void run() {
                System.out.println(">>>>主任务执行了!<<<<");
        }
}

/**
* 子任务
*/

class SubTask extends Thread {
        private String name;
        private CyclicBarrier cb;

        SubTask(String name, CyclicBarrier cb) {
                this.name = name;
                this.cb = cb;
        }

        public void run() {
                System.out.println("[子任务" + name + "]开始执行了!");
                for (int i = 0; i < 999999; i++) ;    //模拟耗时的任务
                System.out.println("[子任务" + name + "]开始执行完成了,并通知障碍器已经完成!");
                try {
                        //通知障碍器已经完成
                        cb.await();
                } catch (InterruptedException e) {
                        e.printStackTrace();
                } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                }
        }
}

 
运行结果:
[子任务E]开始执行了!
[子任务E]开始执行完成了,并通知障碍器已经完成!
[子任务F]开始执行了!
[子任务G]开始执行了!
[子任务F]开始执行完成了,并通知障碍器已经完成!
[子任务G]开始执行完成了,并通知障碍器已经完成!
[子任务C]开始执行了!
[子任务B]开始执行了!
[子任务C]开始执行完成了,并通知障碍器已经完成!
[子任务D]开始执行了!
[子任务A]开始执行了!
[子任务D]开始执行完成了,并通知障碍器已经完成!
[子任务B]开始执行完成了,并通知障碍器已经完成!
[子任务A]开始执行完成了,并通知障碍器已经完成!
>>>>主任务执行了!<<<<

Process finished with exit code 0

 
从执行结果可以看出,所有子任务完成的时候,主任务执行了,达到了控制的目标。

本文出自 “熔 岩” 博客,请务必保留此出处http://lavasoft.blog.51cto.com/62575/222738

Java线程:新特征-原子量

Java线程:新特征-原子量
 
所谓的原子量即操作变量的操作是“原子的”,该操作不可再分,因此是线程安全的。
 
为何要使用原子变量呢,原因是多个线程对单个变量操作也会引起一些问题。在Java5之前,可以通过volatile、synchronized关键字来解决并发访问的安全问题,但这样太麻烦。
Java5之后,专门提供了用来进行单变量多线程并发安全访问的工具包java.util.concurrent.atomic,其中的类也很简单。
 

下面给出一个反面例子(切勿模仿):
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;

/**
* Java线程:新特征-原子量
*
* @author leizhimin 2009-11-6 9:53:11
*/

public class Test {
        public static void main(String[] args) {
                ExecutorService pool = Executors.newFixedThreadPool(2);
                Runnable t1 = new MyRunnable("张三", 2000);
                Runnable t2 = new MyRunnable("李四", 3600);
                Runnable t3 = new MyRunnable("王五", 2700);
                Runnable t4 = new MyRunnable("老张", 600);
                Runnable t5 = new MyRunnable("老牛", 1300);
                Runnable t6 = new MyRunnable("胖子", 800);
                //执行各个线程
                pool.execute(t1);
                pool.execute(t2);
                pool.execute(t3);
                pool.execute(t4);
                pool.execute(t5);
                pool.execute(t6);
                //关闭线程池
                pool.shutdown();
        }
}

class MyRunnable implements Runnable {
        private static AtomicLong aLong = new AtomicLong(10000);        //原子量,每个线程都可以自由操作
        private String name;                //操作人
        private int x;                            //操作数额

        MyRunnable(String name, int x) {
                this.name = name;
                this.x = x;
        }

        public void run() {
                System.out.println(name + "执行了" + x + ",当前余额:" + aLong.addAndGet(x));
        }
}

 
运行结果:
李四执行了3600,当前余额:13600
王五执行了2700,当前余额:16300
老张执行了600,当前余额:16900
老牛执行了1300,当前余额:18200
胖子执行了800,当前余额:19000
张三执行了2000,当前余额:21000

Process finished with exit code 0

 
张三执行了2000,当前余额:12000
王五执行了2700,当前余额:18300
老张执行了600,当前余额:18900
老牛执行了1300,当前余额:20200
胖子执行了800,当前余额:21000
李四执行了3600,当前余额:15600

Process finished with exit code 0

 
张三执行了2000,当前余额:12000
李四执行了3600,当前余额:15600
老张执行了600,当前余额:18900
老牛执行了1300,当前余额:20200
胖子执行了800,当前余额:21000
王五执行了2700,当前余额:18300

Process finished with exit code 0

 
从运行结果可以看出,虽然使用了原子量,但是程序并发访问还是有问题,那究竟问题出在哪里了?
 
这里要注意的一点是,原子量虽然可以保证单个变量在某一个操作过程的安全,但无法保证你整个代码块,或者整个程序的安全性。因此,通常还应该使用锁等同步机制来控制整个程序的安全性。
 
下面是对这个错误修正:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.AtomicLong;

/**
* Java线程:新特征-原子量
*
* @author leizhimin 2009-11-6 9:53:11
*/

public class Test {
        public static void main(String[] args) {
                ExecutorService pool = Executors.newFixedThreadPool(2);
                Lock lock = new ReentrantLock(false);
                Runnable t1 = new MyRunnable("张三", 2000,lock);
                Runnable t2 = new MyRunnable("李四", 3600,lock);
                Runnable t3 = new MyRunnable("王五", 2700,lock);
                Runnable t4 = new MyRunnable("老张", 600,lock);
                Runnable t5 = new MyRunnable("老牛", 1300,lock);
                Runnable t6 = new MyRunnable("胖子", 800,lock);
                //执行各个线程
                pool.execute(t1);
                pool.execute(t2);
                pool.execute(t3);
                pool.execute(t4);
                pool.execute(t5);
                pool.execute(t6);
                //关闭线程池
                pool.shutdown();
        }
}

class MyRunnable implements Runnable {
        private static AtomicLong aLong = new AtomicLong(10000);        //原子量,每个线程都可以自由操作
        private String name;                //操作人
        private int x;                            //操作数额
        private Lock lock;

        MyRunnable(String name, int x,Lock lock) {
                this.name = name;
                this.x = x;
                this.lock = lock;
        }

        public void run() {
                lock.lock();
                System.out.println(name + "执行了" + x + ",当前余额:" + aLong.addAndGet(x));
                lock.unlock();
        }
}

 
执行结果:
张三执行了2000,当前余额:12000
王五执行了2700,当前余额:14700
老张执行了600,当前余额:15300
老牛执行了1300,当前余额:16600
胖子执行了800,当前余额:17400
李四执行了3600,当前余额:21000

Process finished with exit code 0

 
这里使用了一个对象锁,来控制对并发代码的访问。不管运行多少次,执行次序如何,最终余额均为21000,这个结果是正确的。
 
有关原子量的用法很简单,关键是对原子量的认识,原子仅仅是保证变量操作的原子性,但整个程序还需要考虑线程安全的。
 

本文出自 “熔 岩” 博客,请务必保留此出处http://lavasoft.blog.51cto.com/62575/222541

Java线程:新特征-条件变量

Java线程:新特征-条件变量
 
条件变量是Java5线程中很重要的一个概念,顾名思义,条件变量就是表示条件的一种变量。但是必须说明,这里的条件是没有实际含义的,仅仅是个标记而已,并且条件的含义往往通过代码来赋予其含义。
 
这里的条件和普通意义上的条件表达式有着天壤之别。
 
条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上 调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问 竞争资源的安全。
 
条件变量的出现是为了更精细控制线程等待与唤醒,在Java5之前,线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法,这样的处理不够精细。
 
而在Java5中,一个锁可以有多个条件,每个条件上可以有多个线程等待,通过调用await()方法,可以让线程在该条件下等待。当调用signalAll()方法,又可以唤醒该条件下的等待的线程。有关Condition接口的API可以具体参考JavaAPI文档。
 
条件变量比较抽象,原因是他不是自然语言中的条件概念,而是程序控制的一种手段。
 
下面以一个银行存取款的模拟程序为例来揭盖Java多线程条件变量的神秘面纱:
 
有一个账户,多个用户(线程)在同时操作这个账户,有的存款有的取款,存款随便存,取款有限制,不能透支,任何试图透支的操作都将等待里面有足够存款才执行操作。
 
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* Java线程:条件变量
*
* @author leizhimin 2009-11-5 10:57:29
*/

public class Test {
        public static void main(String[] args) {
                //创建并发访问的账户
                MyCount myCount = new MyCount("95599200901215522", 10000);
                //创建一个线程池
                ExecutorService pool = Executors.newFixedThreadPool(2);
                Thread t1 = new SaveThread("张三", myCount, 2000);
                Thread t2 = new SaveThread("李四", myCount, 3600);
                Thread t3 = new DrawThread("王五", myCount, 2700);
                Thread t4 = new SaveThread("老张", myCount, 600);
                Thread t5 = new DrawThread("老牛", myCount, 1300);
                Thread t6 = new DrawThread("胖子", myCount, 800);
                //执行各个线程
                pool.execute(t1);
                pool.execute(t2);
                pool.execute(t3);
                pool.execute(t4);
                pool.execute(t5);
                pool.execute(t6);
                //关闭线程池
                pool.shutdown();
        }
}

/**
* 存款线程类
*/

class SaveThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        SaveThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        }

        public void run() {
                myCount.saving(x, name);
        }
}

/**
* 取款线程类
*/

class DrawThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        DrawThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        }

        public void run() {
                myCount.drawing(x, name);
        }
}

/**
* 普通银行账户,不可透支
*/

class MyCount {
        private String oid;                         //账号
        private int cash;                             //账户余额
        private Lock lock = new ReentrantLock();                //账户锁
        private Condition _save = lock.newCondition();    //存款条件
        private Condition _draw = lock.newCondition();    //取款条件

        MyCount(String oid, int cash) {
                this.oid = oid;
                this.cash = cash;
        }

        /**
         * 存款
         *
         * @param x        操作金额
         * @param name 操作人
         */

        public void saving(int x, String name) {
                lock.lock();                        //获取锁
                if (x > 0) {
                        cash += x;                    //存款
                        System.out.println(name + "存款" + x + ",当前余额为" + cash);
                }
                _draw.signalAll();            //唤醒所有等待线程。
                lock.unlock();                    //释放锁
        }

        /**
         * 取款
         *
         * @param x        操作金额
         * @param name 操作人
         */

        public void drawing(int x, String name) {
                lock.lock();                                 //获取锁
                try {
                        if (cash – x < 0) {
                                _draw.await();             //阻塞取款操作
                        } else {
                                cash -= x;                     //取款
                                System.out.println(name + "取款" + x + ",当前余额为" + cash);
                        }
                        _save.signalAll();             //唤醒所有存款操作
                } catch (InterruptedException e) {
                        e.printStackTrace();
                } finally {
                        lock.unlock();                     //释放锁
                }
        }
}

 
 
李四存款3600,当前余额为13600
张三存款2000,当前余额为15600
老张存款600,当前余额为16200
老牛取款1300,当前余额为14900
胖子取款800,当前余额为14100
王五取款2700,当前余额为11400

Process finished with exit code 0

 
假如我们不用锁和条件变量,如何实现此功能呢?下面是实现代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* Java线程:不用条件变量
*
* @author leizhimin 2009-11-5 10:57:29
*/

public class Test {
        public static void main(String[] args) {
                //创建并发访问的账户
                MyCount myCount = new MyCount("95599200901215522", 10000);
                //创建一个线程池
                ExecutorService pool = Executors.newFixedThreadPool(2);
                Thread t1 = new SaveThread("张三", myCount, 2000);
                Thread t2 = new SaveThread("李四", myCount, 3600);
                Thread t3 = new DrawThread("王五", myCount, 2700);
                Thread t4 = new SaveThread("老张", myCount, 600);
                Thread t5 = new DrawThread("老牛", myCount, 1300);
                Thread t6 = new DrawThread("胖子", myCount, 800);
                //执行各个线程
                pool.execute(t1);
                pool.execute(t2);
                pool.execute(t3);
                pool.execute(t4);
                pool.execute(t5);
                pool.execute(t6);
                //关闭线程池
                pool.shutdown();
        }
}

/**
* 存款线程类
*/

class SaveThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        SaveThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        }

        public void run() {
                myCount.saving(x, name);
        }
}

/**
* 取款线程类
*/

class DrawThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        DrawThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        }

        public void run() {
                myCount.drawing(x, name);
        }
}

/**
* 普通银行账户,不可透支
*/

class MyCount {
        private String oid;                         //账号
        private int cash;                             //账户余额

        MyCount(String oid, int cash) {
                this.oid = oid;
                this.cash = cash;
        }

        /**
         * 存款
         *
         * @param x        操作金额
         * @param name 操作人
         */

        public synchronized void saving(int x, String name) {
                if (x > 0) {
                        cash += x;                    //存款
                        System.out.println(name + "存款" + x + ",当前余额为" + cash);
                }
                notifyAll();            //唤醒所有等待线程。
        }

        /**
         * 取款
         *
         * @param x        操作金额
         * @param name 操作人
         */

        public synchronized void drawing(int x, String name) {
                if (cash – x < 0) {
                        try {
                                wait();
                        } catch (InterruptedException e1) {
                                e1.printStackTrace();
                        }
                } else {
                        cash -= x;                     //取款
                        System.out.println(name + "取款" + x + ",当前余额为" + cash);
                }
                notifyAll();             //唤醒所有存款操作
        }
}

 
输出结果为:
李四存款3600,当前余额为13600
王五取款2700,当前余额为10900
老张存款600,当前余额为11500
老牛取款1300,当前余额为10200
胖子取款800,当前余额为9400
张三存款2000,当前余额为11400

Process finished with exit code 0

 
结合先前同步代码知识,举一反三,将此例改为同步代码块来实现,代码如下:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* Java线程:改为同步代码块
*
* @author leizhimin 2009-11-5 10:57:29
*/

public class Test {
        public static void main(String[] args) {
                //创建并发访问的账户
                MyCount myCount = new MyCount("95599200901215522", 10000);
                //创建一个线程池
                ExecutorService pool = Executors.newFixedThreadPool(2);
                Thread t1 = new SaveThread("张三", myCount, 2000);
                Thread t2 = new SaveThread("李四", myCount, 3600);
                Thread t3 = new DrawThread("王五", myCount, 2700);
                Thread t4 = new SaveThread("老张", myCount, 600);
                Thread t5 = new DrawThread("老牛", myCount, 1300);
                Thread t6 = new DrawThread("胖子", myCount, 800);
                //执行各个线程
                pool.execute(t1);
                pool.execute(t2);
                pool.execute(t3);
                pool.execute(t4);
                pool.execute(t5);
                pool.execute(t6);
                //关闭线程池
                pool.shutdown();
        }
}

/**
* 存款线程类
*/

class SaveThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        SaveThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        }

        public void run() {
                myCount.saving(x, name);
        }
}

/**
* 取款线程类
*/

class DrawThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        DrawThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        }

        public void run() {
                myCount.drawing(x, name);
        }
}

/**
* 普通银行账户,不可透支
*/

class MyCount {
        private String oid;                         //账号
        private int cash;                             //账户余额

        MyCount(String oid, int cash) {
                this.oid = oid;
                this.cash = cash;
        }

        /**
         * 存款
         *
         * @param x        操作金额
         * @param name 操作人
         */

        public void saving(int x, String name) {
                if (x > 0) {
                        synchronized (this) {
                                cash += x;                    //存款
                                System.out.println(name + "存款" + x + ",当前余额为" + cash);
                                notifyAll();            //唤醒所有等待线程。
                        }
                }
        }

        /**
         * 取款
         *
         * @param x        操作金额
         * @param name 操作人
         */

        public synchronized void drawing(int x, String name) {
                synchronized (this) {
                        if (cash – x < 0) {
                                try {
                                        wait();
                                } catch (InterruptedException e1) {
                                        e1.printStackTrace();
                                }
                        } else {
                                cash -= x;                     //取款
                                System.out.println(name + "取款" + x + ",当前余额为" + cash);
                        }
                }
                notifyAll();             //唤醒所有存款操作
        }
}

 
李四存款3600,当前余额为13600
王五取款2700,当前余额为10900
老张存款600,当前余额为11500
老牛取款1300,当前余额为10200
胖子取款800,当前余额为9400
张三存款2000,当前余额为11400

Process finished with exit code 0

 
对比以上三种方式,从控制角度上讲,第一种最灵活,第二种代码最简单,第三种容易犯错。
 

本文出自 “熔 岩” 博客,转载请与作者联系!