您的位置:首页 > 编程语言 > Java开发

JAVA多线程基础(二)

2014-11-24 19:19 260 查看
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。

相关DEMO演练下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: