java多线程

线程优先级:默认情况下,一个线程继承它的父线程的优先级。

每当线程调度器有机会选择新线程时,它首先选择具有较高优先级的线程。

可以通过调用

thread.SetDaemon(true)

将线程转换为守护线程。守护线程的唯一用途是为其他线程提供服务。当只剩下守护线程时,虚拟机就退出了。

守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。

线程的run方法不能抛出任何被检测的异常,但是不被检测的异常会导致线程终止,不需要任何catch子句来处理可以被传播的异常,线程在死亡之前,异常被专递到一个用于捕获异常的处理器。改处理器必须属于一个实现Tread.UncaughtExceptionHandler接口的类。

java有两种方式来完成防止代码块受并发访问的干扰:

1、synchronized关键字

2、ReentrantLock类             注意: 每个A对象具有自己的ReentrantLock对象,如果两个线程试图访问同一个A对象,那么锁以串行的方式提供服务。但是,如果两个线程访问不同的A对象,每个线程的到不同的锁对象,两个线程都不会发生阻塞。(我的理解:一个对象也可以具有多个ReentrantLock对象)


锁是可重入的,因为线程可以重复地获得已经持有的锁,锁保持一个持有计数来跟踪对lock方法的嵌套调用。被一个锁保护的代码可以调用另一个使用相同锁的方法。

//8-5 16:50

通常,线程进入临界区,却发现某一条件满足之后它才能执行,要使用一个条件对象来管理那些已经获得了一个锁但是却不能做有用工作的线程。

一个锁对象可以有一个或多个相关的条件对象,可以用newCondition方法获得一个条件对象。

使用锁对象创建一个条件对象,如果条件不满足,调用条件对象的await()方法,当前线程现在被阻塞了,并放弃了锁,等待获得锁的线程和调用await方法的线程存在本质上的不同。一旦一个线程调用await方法,它进入该条件的等待集。当锁可用时,该线程不能马上解除阻塞。相反,它处于阻塞状态,直到另一个线程调用了同一条件上的signalALL方法时为止。

条件对象调用signalAll()方法,这一调用重新激活因为这一条件而等待的所有线程。当这些线程从等待集中移出时,它们再次成为可运行的,调度器将再次激活它们。同时,它们将试图重新进入该对象。一旦锁成为可用的,它们中的某个将从await调用返回,获得该锁并从被阻塞的地方继续执行。此时,线程应该再次测试该条件。由于无法确保该条件被满足-------signalAll方法仅仅是通知正在等待的线程:此时有可能已经满足条件,值得再次去检测该条件。

至关重要的是最终需要某个其他线程调用signalAll方法。当一个线程调用await时,它没有办法重新激活自身。它寄希望于其他线程。如果没有其他线程来重新激活等待的线程,它就永远不再运行了。这将导致令人不快的死锁现象。

如果所有其他线程被阻塞,最后一个活动线程在解除其他线程的阻塞状态之前就调用了await方法,那么它也被阻塞。没有任何线程可以解除其他线程的阻塞,那么该程序就挂起了。

在对象的状态有利于等待线程的方向改变时调用signalAll方法。signalAll方法不会立即激活一个等待线程。它仅仅解除等待线程的阻塞,一遍这些线程可以在当前线程退出同步方法之后,通过竞争实现对对象的访问。另一个方法signal,则是随机解除等待集中某个线程的阻塞状态。这比解除所有线程的阻塞更加有效,但也存在危险。如果所及选择的线程发现自己任然不能运行,那么它再次被阻塞。如果没有其他线程再次调用signal,那么系统就死锁了。

1、锁用来保护代码片段,任何时刻只能有一个线程执行被保护的代码。

2、锁可以管理试图进入被保护代码段的线程。

3、锁可以拥有一个或多个相关的条件对象。

4、每个条件对象管理那些已经进入被保护的代码段但还不能运行的线程。


JAVA中每一个对象都有一个内部锁,如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。也就是说,要调用这个方法,线程必须获得内部的对象锁。

内部对象锁只有一个相关条件,wait方法添加一个线程到等待集中,notifyAll/notify方法解除等待线程的阻塞状态。

wait、notifyAll和notify方法是Object类的final方法。

将静态方法声明为synchronized也是合法的,如果调用这种方法,该方法获得相关的类对象的内部锁。没有其他线程可以调用同一个类的这个或任何其他的同步静态方法。

内部锁和条件存在一些局限。

1、不能中断一个正在试图获得锁的线程。

2、试图获得锁时不能设定超时。

3、每个锁仅有单一的条件,可能不够。

建议:

1、最好不使用lock/condition也不使用synchronized关键字。建议使用java.unit.concurrent包中的机制。

2、如果synchronized适合成绩,尽量使用它。

3、如果特别需要lock/condition结果提供独有特训时,才使用。


同步阻塞:

每一个java对象有一个锁。线程可以通过调用同步方法获得锁。还有另一种机制可以获得锁,通过进入一个同步阻塞。

synchroinzed(obj){

critical section

}

它获取obj的锁,常常在类定义中会定义一个object对象,它被创建仅仅是用来使用每个java对象持有的锁。这种方式呗称之为“客户端锁定”,但是客户端锁定依赖于所有对关键信息进行修改的方法都使用内部锁。


监视器

锁和条件是线程同步的强大工具,但是他们不是面向对象的。如何在不需要程序员考虑如何加锁的情况下,就可以保证多线程的安全性,最成功的解决方案是:监视器。

监视器具有如下特性:

1、监视器是只包含私有域的类

2、每个监视器类的对象有一个相关的锁

3、使用该锁对所有的方法进行加锁。A对象的锁是在方法调用时开始时自动获得,并且当方法返回时自动释放该锁。

4、该锁可以有任意多个相关条件。


java对象不同于监视器,从而使得线程的安全性降低:

1、域不要求必须是private

2、方法不要求必须是 synchronized

3、内部锁对客户是可用的

volatile关键字为实例域的同步访问提供一种免锁机制,那么编译器和虚拟机就知道该域是可能被另一个线程并发更新的。

在如下3个条件下,域的并发访问是安全的:

1、域是final,并且在构造器调用完成之后是安全的。

2、对域的访问由公有的锁进行保护。

3、域是volatile的







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值