关于JAVA多线程的那些事__初心者

前言

  其实事情的经过也许会复杂了点,这事还得从两个月前开始说。那天,我果断不干IT支援。那天,我立志要做一个真正的程序猿。那天,我26岁11个月。那天,我开始看Android。那天,我一边叨念着有朋自远方来,一边投身了JAVA的怀抱。那天,一切将会改变。

  好吧,反正总的来说就是时隔4年半,我又开始搞JAVA了。Eclipse还是Eclipse;NetBeans还是NetBeans;Java被收之后已经来到了7,现在是8;在入手了几本JAVA的书籍后发现《JAVA编程思想》还是这么伟大;开始了新的路途--Android。

  下面可能会涉及到一些跟其他框架或者语言比较的情况,比如当下挺火的HTML5,比如越来越火的U3D,比如之前一直从事的WEB应用。然后是我的老朋友JAVA,还有他介绍给我认识的新朋友Android跟之前我或深或浅涉猎过的这些奇奇怪怪的东西做一些比较。当然,主要论述的都是JAVA关于线程这块的一些或技术或心路的历程吧。

我与多线程的那些事

  先不从项目说,先说说我对多线程的恐惧。遥想当年读书的时候,JAVA课程设计,老湿给了一个题目,我觉得没啥难度,然后自己立了一个题目,叫两人对战游戏,就是控制两个人跑来跑去然后有攻击防御和技能三个按键,反正就是很弱智的那种。然后老湿说要求用TXT来编,用cmd来调,给一个还是两个星期还是一个月时间去弄,反正我就在最后一个星期管这事。然后我拿着一本JAVA编程思想,两天就把UI写起来,然后就是地狱般的4天,各种各样稀奇古怪的BUG,debug之后触发了更多的bug,然后到了交任务的时候我已经燃烧殆尽了~ 然后由于当初没选老湿的题目已经让老湿很不爽,现在做的这个东西奇奇怪怪的当然被狠批一顿。给了个60多分了事。事后我自己努力了一把,然后就放弃了,删源码,删程序,各种删~ 然后各种自卑,各种觉得自己就是个哔哔,然后看到多线程就尿了~

  然后到了工作写的第一个系统,库存ERP系统(这里很感激公司能给一个实习生这么大的空间去发挥啊~)。忽略掉前面那些技术选型啊,噼里啪啦的东西之后到了数据访问这一环,我半天时间就写完了。用的是ASP.NET。但是这里出问题了,因为我用的是直接提交一条SQL语句去执行操作的,然后根据返回的值来判定后面执行的SQL操作。那时我突然想到一个问题,如果两个用户同时用我的SQL语句去操作,而操作的资源这个时候判定是不对的,但是可能由于另外一个用户的同时操作使得这个判定通过了,这怎么弄?(简单来说就是一个同步的问题,那时候还不知道~)

  然后就是.NET实现原子性啊,.NET实现事务啊噼里啪啦的东西。到了最后,我把业务逻辑写在了T-SQL存储过程里面,因此这里面的东西充斥着begin tran a; submit tran a; rollback tran a;然后还特意研究了T-SQL事务处理的递归性(具体可以参阅我之前博客的这篇文章:SQL存储过程递归下的事务处理(本身的缺陷还是蛮大的))。然后各种噼里啪啦之后,写T-SQL各种顺手。然后各种各样的逻辑全部写存储过程,然后练就了一双写T-SQL的好手~~

  在往后是随着经验值的上涨,我开始密谋架构ERP内核的时候做的单例模式,用于管理用户登录信息。这个时候出现了一种叫线程安全的单例模式,然后就是lock(object){...},不求甚解,直接就上了。关于“线程安全的单例模式”不懂的可以直接复制去问度娘。那时做出来的时候特嚣张,虽然一知半解,也去忽悠别人了~ 反正是能跑,你管俺是真懂的还是蒙中的~

  直到……

初体验

  各种蛋疼的人事,各种无聊的纠纷,各种倔强的泪水之后,俺从事Android了,俺搞JAVA了~

  说下Android跟U3D UI线程方面的不同吧,纯个人或别人观点,有错的话请温柔地指出。U3D的UI线程我们公司的一位专门从事这个领域的哥们说U3D的线程就是一个大轮询,往里面塞任务。简单来说U3D的UI是跑一条线程的(其实想想也是合理的,因为U3D支持多平台发布,其中就包括了Web平台,而JAVAScript就是单线程的)。而Android的UI线程是多线程的,其他线程想要调用Android的UI线程,那就得用handler了,貌似是个钩子的方式做嵌入(详细情况可以参考这里: Android之Handler用法总结 还有钩子的介绍,设计模式之:模板模式)。那么从上面的信息得知Android的UI极有可能是维护一个线程池的。(纯属个人推断,未经考察证实)而Android除了上面的Handler(在其他线程跑UI)之外貌似还提供了一些不错的在UI内部跑其他线程的支援。

  然后虽然了解了上面的这些,但是项目的内核还得用JAVA多线程来做,而且跟UI目测没有半毛钱关系。因此吧,就只能老老实实打基础了。有个同事的QQ签名是:当你的才华不足以支撑你的野心时,那你就得多看点书。我觉得很有道理,因此我看书……

Runnable&Thread

  开始好多人都说JAVA多线程就是实现Runnable接口或者写Thread类。但是这种说法有时会混熬我们的思维,反正我那时候就是把这两者当成平衡的来看,但其实从现在的应用来说Runnable更多的应该比喻成一个任务(Task),而Thread是管理这个任务的容器。有兴趣的人可以去搜下Thread.start()和Runnable.run()之间的区别。因此很多写过多线程的程序员都会有这种感觉:Runnable用的比Thread要多。而在《JAVA编程思想》里面更是推荐大家用所谓的线程池来管理自己的线程。这里引出了一个概念:线程池。这里可以得出一个结论:线程的管理和线程本身已经分离了。因此这里叫线程已经显得不合适了,这时候换一个称呼可能更加的有助于我们对这个事情的理解。比如把一个Runnable的实例叫“任务”。

 1      private Runnable aNewTask = new Runnable()
 2      {
 3          @Override
 4          public void run()
 5          {
 6              //跑一些奇怪的东西
 7              System.out.println("哈哈");
 8          }
 9      }
10     ExecutorService exec = Executors.newCachedThreadPool();
11     exec.execute(aNewTask);
12     exec.shutdown();

  上述就是把一个任务aNewTask放到exec的一个池里面跑,shutdown是关闭池,当然也可以不关闭啦。池有很多种,具体可以看文档或者JAVA编程思想吧。

生产者-消费者模型

  这种模型适合的情景:一个资源,两条线程,一条线程负责读,一条线程负责写。

  具体可以参阅下面的文章: java实现生产者消费者问题

  文章里面提到几种方法,我用到第三种,因此下面是基于JAVA的堵塞队列LinkedBlockingQueue来讨论的。这里的生产者-消费者模型说的比较少,但是他是我整个模型的核心思想。这里有几点我项目的时候犯过的错这里提出来一下:

  1. LinkedBlockingQueue里面我存的是一个数组,就是说这是一个数组的队列。而每当我从另外的地方接受了数据之后就传入这个队列,这时候需要把这个传入的数组clone()一次。因为直接传入的那只是一个引用,而非实体,极有可能这个引用的实体在递交给队列之后就会销毁了。这时就只剩下一个地址了。

  2. LinkedBlockingQueue是线程安全的,但是如果想要确保一次任务或者一个循环里面多次调用的时候不受干扰,那么还是得用同步锁synchronized去锁定循环体执行的代码。有个资深程序员,同时也是我同学,说:尽量不要用synchronized去锁定资源。而两一位更加资深的工程师也说锁会产生格外的损耗,能不用就不用。但是显然到了我项目里面还得要读写的时候锁死,否则数据就会刷的不整齐了~ 刷不整齐,小伙伴们又有意见了~ 现在想想,其实也真没有锁定的必要啊~ 至于数据会不会丢帧就要留给测试了~。

  3. 虽然跟这个模型不相干,但是还是记录一下。在实施的过程中,我机(dou)智(bi)地把类似于 exec.execute(aNewTask); 这种语句锁了。然后症状就是必须要等这个任务执行完了,这个锁别人的线程才会得到释放~。。可伶我这个一秒锁人家一下的社会青年啊~ 锁出翔了~

项目

  先上一张最终的收发设计图吧~

  

  中间那条竖线的意思是接受一个响应的时候才发送下一条数据,夜已深~ 不多介绍项目的细节了。因为整个项目的实施过程基本可以另外再起一篇长文了。比如最开始思考的无堵塞模型(这个非常好玩~~),然后后来编码第一版的基于Channel的发送堵塞模型,然后发现原来下面的东西没有想象中的强悍(羞~),做成这一版的基于Module的发送堵塞模型。好吧写到这里感觉已经在放嘲讽了~

总结

  1. 多线程很好玩,思考程序很开心。

  2. 帅气的喊一句,当手抚键盘的时候,吾已为神。

  3. 白赖先生听到之后投来一个看手(S)表(B)的眼神~

-- 原创的哟,转载请加出处哟 http://www.cnblogs.com/gssl/p/3854512.html 虽然没什么人转的哟 呵呵--

关于JAVA多线程的那些事__初心者

时间: 2024-08-10 23:05:46

关于JAVA多线程的那些事__初心者的相关文章

java多线程那点事

屌丝程序员们对自己的技术能力总是毫不掩饰的高调,更有甚者每当完成一个简单的功能或算法实现,恨不得从工位上跳起来,生怕谁不知道一样,心情能理解,但个人完全鄙视这种行为.说到底,大家日常的coding,大多在单线程下执行,代码书写的顺序即执行的顺序,很多时候也是我们解决问题的逻辑顺序.有很多代码,如果考虑多线程,从并发的角度去实现,伪"大牛"们可能就要原形毕露了,很多同学更是束手无策.那么,多线程真的那么可怕么?接下来本人 把自己的一些理解分享出来,如有不当,欢迎指正. java多线程问题

Java多线程导致的的一个事物性问题

业务场景 我们现在有一个类似于文件上传的功能,各个子站点接受业务,业务上传文件,各个子站点的文件需要提交到总站点保存,文件是按批次提交到总站点的,也就是说,一个批次下面约有几百个文件. 考虑到白天提交这么多文件会影响到子站点其他系统带宽,我们将分站点的文件提交到总站点这个操作过程独立出来,放到晚上来做,具体时间是晚上7:00到早上7:00. 这个操作过程我们暂且称作"排程". 排程在运行之后,先获取所有需要上传到总站点的批次信息,拿到批次信息之后,将这个批次表的状态置为正在同步数据,这

Rhythmk 一步一步学 JAVA (21) JAVA 多线程

1.JAVA多线程简单示例 1.1 .Thread  集成接口 Runnable 1.2 .线程状态,可以通过  Thread.getState()获取线程状态: New (新创建) Runnable (可以运行) Blocked  (被阻塞) Waiting  (等待) Timed waiting (计时等待) Terminated  (被终止) ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

【转】 Java 多线程之一

转自   Java 多线程 并发编程 一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种资源和状态信息,包括打开的文件.子进程和信号处理. 线程:表示程序的执行流程,是CPU调度执行的基本单位:线程有自己的程序计数器.寄存器.堆栈和帧.同一进程中的线程共用相同的地址空间,同时共享进进程锁拥有的内存和其他资源. 2.Java标准库提供了进程和线程相关

java多线程(二)——用到的设计模式

接上篇:java多线程(一)http://www.cnblogs.com/ChaosJu/p/4528895.html java实现多线程的方式二,实现Runable接口用到设计模式——静态代理模式 一.代理模式 代理模式的定义 代理模式(Proxy Pattern)是对象的结构型模式,代理模式给某一个对象提供了一个代理对象,并由代理对象控制对原对象的引用. 代理模式不会改变原来的接口和行为,只是转由代理干某件事,代理可以控制原来的目标,例如:代理商,代理商只会卖东西,但并不会改变行为,不会制造

java从基础知识(十)java多线程(下)

首先介绍可见性.原子性.有序性.重排序这几个概念 原子性:即一个操作或多个操作要么全部执行并且执行的过程不会被任何因素打断,要么都不执行. 可见性:一个线程对共享变量值的修改,能够及时地被其它线程看到 共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量 每个线程都有自己的工作内存,存有主内存中共享变量的副本,当工作内存中的共享变量改变,会主动刷新到主内存中,其它工作内存要使用共享变量时先从主内存中刷新共享变量到工作内存,这样就保证了共享变量的可见性. 可

java多线程并发编程与CPU时钟分配小议

我们先来研究下JAVA的多线程的并发编程和CPU时钟振荡的关系吧 老规矩,先科普 我们的操作系统在DOS以前都是单任务的 什么是单任务呢?就是一次只能做一件事 你复制文件的时候,就不能重命名了 那么现在的操作系统,我一边在这边写BLOG,一边听歌,一边开着QQ,一边…………………… 显然,现在的操作系统都是多任务的操作系统 操作系统对多任务的支持是怎么样的呢? 每打开一个程序,就启动一个进程,为其分配相应空间(主要是运行程序的内存空间) 这其实就支持并发运行了 CPU有个时钟频率,表示每秒能执行

java 多线程详解

线程的同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问. 由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套机制就是 synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synch

java多线程使用学习笔记

初学Java多线程,后续继续改进 一,Callable Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其他线程执行的任务 Callable和Runnable的区别如下: 1.Callable定义的方法是call,而Runnable定义的方法是run. 2.Callable的call方法可以有返回值,而Runnable的run方法不能有返回值. 3.Callable的call方法可抛出异常,而Runnable的run方法不能抛出异常.