您当前的位置: 首页 >  Java

衣舞晨风

暂无认证

  • 1浏览

    0关注

    1156博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Java编程思想读书笔记一:并发

衣舞晨风 发布时间:2017-01-31 20:41:23 ,浏览量:1

1. Thread.yield( )方法

当调用yield()时,即在建议具有相同优先级的其他线程可以运行了,但是注意的是,仅仅是建议,没有任何机制保证你这个建议会被采纳 。一般情况下,对于任何重要的控制或者调用应用时,都不能依赖于yield()。这个方法经常被误用。

2.Runnable接口

当从Runnable导出一个类时,它必须具有run()方法,但是这个方法并无特殊之处——它并不会产生任何内在的线程能力。要实现线程的行为必须显式的讲一个任务附着到线程上。

3.Join()方法

一个线程可以在其他线程之上调用Join()方法,其效果是等待一段时间直到第二个线程结束才继续执行。如果某个线程在另一个线程t上调用t.join(),此线程将被挂起,直到目标线程t结束才恢复(即t.isAlive()返回为假)。也可以在调用join()时带上一个超时参数(单位可以是毫秒,或者毫秒和纳秒),这样如果目标线程在这段时间到期时还没有结束的话,join()方法总能返回。对join()方法的调用可以被中断,做法实是在调用线程上调用interrupt()方法,这时需要调用try-catch子句。

4.互斥量(mutex)

基本上所有的并发模式在解决线程安全问题时,都采用“序列化访问临界资源”的方案,即在同一时刻,只能有一个线程访问临界资源,也称作同步互斥访问。通常这是在代码前加上一条锁语句,使得在一段时间内只有一个线程可以运行这段代码。因为锁语句产生了一种能够互相排斥的效果,所以这种机制被称为互斥量(mutex)。

5.共享资源竞争

一个任务可以多次获得对象的锁。如果一个方法在同一个对象上调用了第二个方法,后者又调用了同一个对象上的另一个方法,就会发生这种情况。JVM负责跟踪对象被加锁的次数,如果一个对象被解锁,计数变为0。在任务第一次给对象加锁的时候,计数变为1。每当这个相同的任务在这个对象上获得锁,计数都会递增。显然,只有首先获得了锁的任务才能允许继续获取多个锁。每当任务离开一个synchronized 方法,计数递减,当计数为0的时候,锁被完全释放,其他任务可以使用此资源。

考虑一下屋子里的浴室:多个人(即多个线程)都希望能单独使用浴室(即共享资源)。为了使用浴室,一个人先敲门,看看是否能使用。如果没人的话,他就进入浴室并且锁上门。这时其它人要使用浴室的话,就会被“阻挡”,所以他们要在浴室门口等待,直到浴室可以使用。

当浴室使用完毕,就该把浴室给其他人使用了,这个比喻就有点不太准确了。事实上,人们并没有排队,我们也不能确定谁将是下一个使用浴室的人,因为线程调度机制并不是确定性的。实际情况是:等待使用浴室的人们簇拥在浴室门口,当锁住浴室门的那个人打开锁准备离开的时候,离门最近的那个人可能进入浴室。如前所述,可以通过yield( )和setPriority( )来给线程调度机制一些建议,但这些建议未必会有多大效果,这取决于你的具体平台和JVM实现。

Java以提供关键字synchronized的形式,为防止资源冲突提供了内置支持。它的行为很像Semaphore类:当线程要执行被synchronized关键字守护的代码片断的时候,它将检查信号量是否存在,然后获取信号量,执行代码,释放信号量。不同的是,synchronized内置于语言,所以这种防护始终存在,不像Semaphore那样要明确使用才能工作。

典型的共享资源是以对象形式存在的内存片断,但也可以是文件,输入/输出端口,或者是打印机。要控制对共享资源的访问,你得先把它包装进一个对象。然后把所有要访问这个资源的方法标记为synchronized。也就是说,一旦某个线程处于一个标记为synchronized的方法中,那么在这个线程从该方法返回之前,其它要调用类中任何标记为synchronized方法的线程都会被阻塞。

一般来说类的数据成员都被声明为私有的,只能通过方法来访问这些数据。所以你可以把方法标记为synchronized来防止资源冲突

6.原子性与可见性(volatile)

当你定义long或double变量时,如果使用 volatile关键字,就会获到(简单的赋值与返回操作的)原子性(注意,在Java SE5之前,volatile一直不能正确的工作)。

volatile关键字还确保了应用中的可视性。如果讲一个域声明为volatile的,那么只要对这个域产生了写操作,那么所有的读操作就都可以看到这个修改。即便使用了本地缓存,情况也确实如此,volatile域会立即被写入到主存中,而读取操作就发生在主存中。

在非volatile域上的原子操作不必刷新到主存中去,因此其他读取该域的任务也不必看到这个新值。如果多个任务在同时访问这个域,那么该域也应该是volatile,否则,这个域就应该只能经由同步来访问。同步也会导致向主存中刷新,因此如果一个域完全有synchronized方法或语句块来保护。那就不必将其设置为是volatile。

一个任务所做的任何写入操作对这个任务来说都是可视的,因此如果它只需要在这个任务内部可视,那么你就不需要将其设置为volatile的。 当一个域的值依赖于他之前的值时(例如递增一个计数器),volatile就无法工作了。如果这个域的值受到其他的域的值的限制,那么volatile也无法工作,例如Range类的lower和upper边界就必须遵循lower

关注
打赏
1647422595
查看更多评论
立即登录/注册

微信扫码登录

0.1400s