Java的多线程及安全性

 

线程 是一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间相互独立。多线程和传统的单线程在程序设计上最大的区别在于,由于各个线程的控制流彼此独立,使得各个线程之间的代码 是乱序执行的。任何线程都有四种状态:产生(New),可执行(Runnable),阻塞(Blocked),死亡(Dead)。
1.Java 的多线程


在 Java中实现多线程有两种方法:第一种方法是继承Thread 类, 覆盖方法run()。即创建Thread类的子类并重写run()方法,加入线程所要执行的代码即可。种方法简单明了,但是它有一个很大的缺点,就是一个 类已经继承了另一个类(如小程序必须继承自Applet类),则无法再继承 Thread类。第二种方法是实现Runnable接口 。 Runnable接口只有一个方法run(),需要声明自己的类来实现Runnable接口并提供这一方法 ,将线程代码写入其中,就完成了这一部分的任务。但是Runnable接口并没有任何对线程的支持,我们还必须创建Thread类的实例,这一点是通过 Thread类的构造函数publicThread(Runnabletar-get)来实现的。


2.线程安全

线程安全 ,是指变量或方法 (这些变量或方法是多线程共享的)可以在多线程的环境下被安全有效的访问。这说明了两方面的问题:
(1)可以从多个线程中调用,无需调用方有任何操作; (2)可以同时被多个线程调用,无需线程之不必要的交互。事实上,线程安全是个很难达到的目标,这可以从类的状态上反映出来,归纳的说,类可分为五种状态:

2.1不可变

一个不可变的对象只要构建正确,其外部可见状态永远不会改变,永远也不会看到它处于不一致的状态。Java类库中大多数基本数值类如 Integer、String和 BigInteger都是原子性的,是不可变的,但 Long和 Double就不能保证其操作的原子性,可在声明变量的时候用volatile关键字。不可变对象上没有副作用,并且缓存不可变对象的引用总是安全的。一 个不可变的对象的一个引用可以自由共享,而不用担心被引用的对象要被修改。


2.2线程安全性类

即对这个类的对象操作序列(读或写其公有字段以及调用其公有方法)都不会使该对象处于无效状态,即任何操作都不会违反该类的任何不可变量、前置条件或者后置条件。


2.3有条件的线程安全类

有条件的线程安全类对于单独的操作可以是线程安全的,但是某些操作序列可能需要外部同步。为了保证其它线程不会在遍历的时候改变集合,进行迭代的线程应该确保它是独占性地访问集合以实现遍历的完整性。通常,独占性的访问是由对锁的同步机制保证的。


2.4线程兼容类

线程兼容类不是线程安全的,但可以通过正确使用同步从而在并发环境中安全地使用。或用一个synchronized 块包含每一个方法调用。


2.5线程对立类

线程对立类是那些不管是否调用了外部同步都不能在并发使用时保证其安全的类。线程对立类很少见,当类修改静态数据,而静态数据会影响在其它线程中执行的其它类的行为时,通常会出现线程对立。


3.多线程的优缺点

何时使用多线程技术,何时避免用它,是我们需要掌握的重要课题。多线程技术是一把双刃剑,在使用时需要充分考虑它的优缺点。
多线程处理可以同时运行多个线程。由于多线程应用程序将程序划分成多个独立的任务,因此可以在以下方面显著提高性能:
(1)多线程技术使程序的响应速度更快 ,因为用户界面可以在进行其它工作的同时一直处于活动状态;

(2)当前没有进行处理的任务时可以将处理器时间让给其它任务;

(3)占用大量处理时间的任务可以定期将处理器时间让给其它任务;

(4)可以随时停止任务;

(5)可以分别设置各个任务的优先级以优化性能。

是否需要创建多个线程取决于各种因素。在以下情况下,最适合采用多线程处理:
(1)耗时或大量占用处理器的任务阻塞用户界面操作;

(2)各个任务必须等待外部资源 (如远程文件或 Internet连接)。


同样的 ,多线程也存在许多缺点 ,在考虑多线程时需要进行充分的考虑。多线程的主要缺点包括:
(1)等候使用共享资源时造成程序的运行速度变慢。这些共享资源主要是独占性的资源 ,如打印机等。

(2)对线程进行管理要求额外的 CPU开销。线程的使用会给系统带来上下文切换的额外负担。当这种负担超过一定程度时,多线程的特点主要表现在其缺点上,比如用独立的线程来更新数组内每个元素。

(3)线程的死锁。即较长时间的等待或资源竞争以及死锁等多线程症状。

(4)对公有变量的同时读或写。当多个线程需要对公有变量进行写操作时,后一个线程往往会修改掉前一个线程存放的数据,从而使前一个线程的参数被修改;另 外 ,当公用变量的读写操作是非原子性时,在不同的机器上,中断时间的不确定性,会导致数据在一个线程内的操作产生错误,从而产生莫名其妙的错误,而这种错误 是程序员无法预知的。

4.结束语
在使用 Java多线程技术时,需要充分的考虑它的方方面面,包括创建线程、对多个线程进行调度和管理、多线程编程的复杂性以及线程切换开销等。多线程的核心是多 个代码块并发执行,本质特点在于各代码块是乱序执行的。是否需要多线程 ,就是要看这是否是它的内在特点。如果用户的应用程序需要多个任务同时进行相应的处理,则使用多线程是较理想的选择 ,需要注意的是在多线程编程时要特别小心处理资源共享问题。在编写类的时候必须记录线程安全性。在编写类时记录类的线程安全性访问的需求和行为可使线程安 全性的最初想法得以保留,使线程安全性记录成为类的说明的一部分。

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页