码迷,mamicode.com
首页 > 编程语言 > 详细

JAVA多线程基础(二)

时间:2014-11-24 21:00:08      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:java   多线程   基础   

        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演练下载


        

JAVA多线程基础(二)

标签:java   多线程   基础   

原文地址:http://blog.csdn.net/ps101505138/article/details/41356769

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!