1、线程同步
多线程编程是有趣的事情,他很容易突然出现“错误情况”,这是由系统的线程调度具有一定的随机性造成的,不过即使程序偶然出现问题,那也是由于编程不当引起的。当使用多个线程来访问同一个数据时,很容易“偶然”出现线程安全问题。
这里通过ATM取钱操作进行同步控制。使用了三种方法:
使用同步代码块,通常推荐使用可能被并发访问的共享资源充当同步监视器。语法格式如下:
public class DrawThread extends Thread{
private Account account ; //账户对象
public void run(){
synchronized (account){
............... //取钱逻辑代码块
}
}
}
使用同步方法,无需显式指定同步监视器,同步方法的同步监视器是this,也就是该对象本身。
public class Account{
...........//此处的代码是属性及方法
public synchronized void draw(double drawAmount){
.......//此处的代码是取钱逻辑
}
}
使用同步锁,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。格式如下:
class X{
private final ReentrantLock lock = new ReentrantLock();
//定义需要保证线程安全的方法
public void m(){
lock.lock(); //加锁
try{
}
finally{
lock.unlock();
}
}
}
2、线程通信
(1)可以借助Object类提供的wait()、notify()和notifyAll()三个方法,这三个方法并不属于Thread类,而是属于Object类。
(2)如果程序不使用synchronized关键字来保证同步,而是直接使用Lock对象来保证同步,则系统中不存在隐式的同步监视器,也就不能使用wait()、notify()和notifyAll()三个方法进行线程通信了。这时可以使用Condition控制线程通信。Condition将同步监视器方法(wait()、notify()和notifyAll())分解成截然不同的对象,以便通过将这些对象与Lock对象组合使用,为每个对象提供多个等待集。在这种情况下,Lock替代了同步方法或同步代码块,Condition替代了同步监视器的功能。Conditon类提供了如下三个方法:await()方法、signal()方法、signalAll()方法。
(3)使用阻塞队列控制线程通信。他的主要作用并不是作为容器,而是作为线程同步的工具,BlockingQueue具有一个特征:当生产者线程试图向BlockingQueue中放入元素时,如果该队列已满,则该线程被阻塞;当消费者线程试图从BlockingQueue中取出元素时,如果该队列已空,则该线程被阻塞。
3、线程池
系统启动一个新线程的成本是比较高的,因为他涉及与操作系统交互。在这种情况下,使用线程池可以很好的提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池。
与数据库连接池类似的是,线程池在系统启动时即创建大量空闲的线程,程序将一个Runnable对象或Callable对象传给线程池,线程池就会启动一个线程来执行他们的run()或call()方法,当run()或call()方法结束后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个Runnable对象的run()或call()方法。
使用线程池来执行线程任务的步骤如下:
(1)调用Executors类的静态工厂方法创建一个ExecurorService对象,该对象代表一个线程池。
(2)创建Runnable实现类或Callable实现类的实例,作为线程执行任务。
(3)调用ExecutorService对象的submit()方法来提交Runnable实例或Callable实例。
(4)当不想提交任何任务时,调用ExccutorService对象的shutdown()方法来关闭线程池。
4、ThreadLocal类
通过ThreadLocal类可以简化多线程编程时的并发访问,使用这个工具类可以很简洁的隔离多线程程序的竞争资源。
ThreadLocal,是Thread Local Variable(线程局部变量)的意思,线程局部变量的功用其实非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立的改变自己的副本,而不会和其他线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量一样。
如果多个线程之间需要共享资源,以达到线程之间的通信功能,就使用同步机制;如果仅仅需要隔离多个线程之间的共享冲突,则可以使用ThreadLocal。
原文地址:http://blog.csdn.net/ps101505138/article/details/41356769