2010.1.4 并发

本文探讨了Java并发编程中的wait和notify方法,指出在调用wait()时对象锁会被释放。同时,线程可以通过notify()、notifyAll()或等待时间到期来结束wait状态并恢复执行。
摘要由CSDN通过智能技术生成

并发

    昨晚和上午粗粗地翻了翻《Thinking in Java》的并发这一章。之所以只是翻了一下,没有深入地学习,是由于两个原因,一是多线程程序用的不多,至少是需要程序员使用Java中多线程的一些高级技术的地方不多;而是多线程的东西很麻烦,花很多时间也不一定能弄懂。其实还有一个原因,就是书中也提到过的,函数式程序设计语言可以使用函数来组织程序,从而将不同的并发任务自动隔离。因此,我觉得这是使用并发的一条更好的路。
    
    并发之所以这么复杂的一个根本原因就是因为计算机自身的图灵机模型就不是并发的,而是严格的顺序执行的。现实中之所以有并发是因为人们将一个大程序中的“弱相关代码段”拆开,在不同的处理器上执行,因此总的控制流程还是线性的。正是这种在理论上没有解决的问题,导致了并发这个看上去挺容易实现的功能产生出这么多的问题。
    正如上面所说,真正意义上的并发是不存在的,我们只能将程序执行过程中的一些弱相关算法段找出来,然后再对其进行组织,使用多线程。
    上面这部分是我以前学到的关于多线程的一些知识,通过学习《Thinking in Java》中的并发这一章,我学到的主要就是一些技术性的问题了。
    初学多线程,很自然想到的一个问题就是“为什么要使用多线程?” ,毕竟,多线程是在多核CPU出现很早以前就有的。书中提到的一种重要解释就是GUI的出现,使得在进程的基础上再划分出一些线程。试想,如果没有线程,那么当一个输入框在等待用户输入时,这个程序就完全停止了,不能在后台继续执行任务。“后台程序”往往指的就是一个线程,在Java中,可以使用setDaemon(true)来将一个线程设置为后台线程。线程的另一个优势是可以更好地模拟现实世界,即在“仿真”上有很大的作用,例如可以在一个交通模拟系统中将每一台移动的车设置为一个线程,从而更好地组织程序。这些原因是我读书后想到的,但应该不是全部原因。
    
    基本的线程机制:
    定义一个任务的基本方法是定义一个实现Runnable接口的类,并实现Runnable中的run()方法。而将Runnable转换为工作任务(线程)的方法是将这个Runnable类传递给一个Threat构造器,如果要执行run()中的方法,只需要调用Thread中的start()方法即可。
    在JavaSE5中,最好使用执行器(Executor)。执行器的构造函数中不需要使用Runnable参数,这个参数是在execute()方法中传递进来的。
    若要使任务有返回值,则不能使用Runnable接口,而使用Callable接口。
    同步里面有两个重要的内容,一个是解决共享资源的竞争,另一个是协作。解决共享资源的竞争是通过“锁机制”来实现的。在Java中有一种优雅地加锁方案,就是使用synchronized关键字。当在对象上调用其任意synchronized方法的时候,此对象都被加锁,这时该对象上的其他synchronized方法只有等到前一个方法调用完毕并释放了锁之后才会被调用。如果只是几条语句要同步,那么可以使用synchronized语句块。使用synchronized的一个重要好处是不必给整个对象加锁。
    除了使用synchronized关键字进行隐式地加锁外,我们还可以使用lock等关键字来进行加锁。
    使用锁可以解决单核CPU机器上的访问冲突问题,如果是多核CPU,还要考虑不一致问题,在Java中解决不一致问题的方法是使用关键字volatile。如果你将一个域(field)声明为volatile的,那么只要对这个域产生了读写操作,那么所有的读操作都会看到这个修改,因为volatile域会立即被写入主存中,而读取操作就发生在主存中。
    
使用同步的时机(什么时候使用同步?):
 Brian的同步规则:
    如果你正在写一个变量,它可能接下来将被另一个线程读取,或者正在读取一个上一次已经被另一个线程写过的变量,那么你必须使用同步,并且,读写线程都必须使用相同的监视器同步。
    协作则使用wait(), notify(), notifyAll()等方法。wait()方法的妙处在于与一个while语句相比,它几乎是不占资源的。wait()与sleep()的不同之处:
  1. 在wait()期间对象锁是释放的。
  2. 可以通过notify(),notifyAll(),或者令时间到期,从wait()中恢复执行。
    关对于共享资源的竞争问题,还有人使用原子性来解决。尤其是有C背景的程序员,因为在C语言中好像大多数语句都只对应一条指令。由于CPU执行的最小单位就是指令,因此使用原子性,经过精心组织,也可以使用原子性来代替同步。但Brian说过这样一句话:
    如果你可以编写可用于现代微处理器的高性能JVM,那么你才有资格去考虑是否可以避免同步。
其他收获:
    wait(), notify(), notifyAll()是Object上的方法,因为锁是Object级别的。这说明Java很早就考虑多线程的问题了。对于现代计算机,很容易就发展到多核的天下,也许再过几年,单核CPU只能在手机等设备中才能找到。因此,在程序中提前加入synchronized关键字,也许在某一天会发挥很大的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值