A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

© kangzhuang112 中级黑马   /  2014-6-21 08:33  /  921 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

在java的历史版本中,有两种创建多线程程序的方法 1.       通过创建Thread类的子类来实现
2.       通过实现Runable接口的类来实现(推荐)
一、通过Thread类实现多线程
  • 设计Thread的子类
  • 根据工作需要重新设计线程的run方法
n  线程类Thread中提供的run是一个空方法。为此,我们可以继承Thread,然后覆盖(override)其中的run,使得该线程能够完成特定的工作。
  • 使用start方法启动线程,将执行权转交到run。
二、通过实现Runnable接口创建线程
n  创建线程最简单的方法就是创建一个实现Runnable 接口的类,这个类仅需实现其中一个run()方法。
n  主要步骤:
1.       创建某个类实现Runnable接口,实现run()方法。
2.       创建Thread对象,用实现Runnable接口的对象作为参数实例化该Thread对象。
3.       调用Thread的start方法。

n  Java有两种创建线程的方法,为什么推荐实现Runnable接口的方式创建线程?
n  Thread类定义了多种方法可以被派生类重载。对于所有的方法,唯一的必须被重载的是run()方法。这当然是实现Runnable接口所需的同样的方法。
n  很多Java程序员认为类仅在它们需要被加强或修改时被扩展。因此,如果你不重载Thread的其他方法,最好通过实现Runnable 接口,来创建线程。
二、使用Executor框架管理线程
n  虽然可以使用Thread类来显示的创建线程,但推荐的做法是使用Executor接口,让它来管理Runnable对象的执行。
n  通常Executor对象会创建并管理一组执行Runnable对象的线程,这组线程被称为线程池。
采用Executor的优势
n  Executor对象能够复用已有的线程,从而消除了为每个任务创建新线程的开销,
n  它能通过优化线程的数量,提高程序性能,保证处理器一直处于忙碌状,而不必创建过多的线程使程序资源耗尽。

步骤:
n  声明一个execute()方法,接收一个Runnable实参,
n  Executor会将传递给它的execute方法的每个Runnable对象赋予线程池中的某个可用线程。
n  如果没有可用线程,Executor会创建一个新线程,或者等待某个线程成为可用的,再将其赋予Runnable对象。


ExecutorService接口
n  该接口扩展了Executor接口,并声明了许多方法用于管理Executor的声明周期。
n  通过Executor类中的静态方法,可用创建实现ExecutorService接口的对象。
n  程序示例: ExecutorServiceTest
线程的同步
n  同一进程的多个线程共享同一存储空间,带来了访问冲突这个严重的问题。
n  有时两个或多个线程可能会试图同时访问一个资源,在此情况下,数据可能会变得不一致。
n  例如,一个线程可能尝试从一个文件中读取数据,而另一个线程则尝试在同一文件中修改数据,
n  某个时刻只允许一个线程排他性的访问操作共享对象的代码,当独占对象的线程在操作对象时,其他线程会一直等待,直到独占对象的那个线程完成了对对象的操作,其他对象才被允许处理该对象,
n  这种方法可以实现多个线程的协同工作,解决冲突问题。
实现线程同步
n  一种常见办法是使用java内置的监控器。
n  每个对象都具有一个监控器和一个监控锁,
n  监控器保证在任何时刻,它的对象的监控锁是由唯一一个线程持有的。
n  这样监控器和监控锁才能用于实现“互斥”。
n  Java中可用使用关键字synchronized为共享资源加锁。
n  synchronized可修饰一个代码块或一个方法,使被修饰对象在任一时刻只能有一个线程访问,从而提供了程序的同步执行功能。

n  两种方式实现同步:
n  使用同步方法:通过在方法声明中加入synchronized关键字来声明synchronized方法
n  public synchronized void methodA() {  }
n  当一个线程调用一个“互斥”方法时,它试图获得该方法锁。如果方法未锁定,则获得使用权,以独占方式运行方法体,运行完释放该方法的锁。如果方法被锁定,则该线程必须等待,直到方法锁被释放时。

n  注意:
n  对方法run( )无法加锁,不可避免冲突;
n  对构造函数不能加锁,否则出现语法错误。
n  synchronized方法虽然可以解决同步的问题,但也存在缺陷,
n  如果一个synchronized方法需要执行很长时间,将会大大影响系统的效率。
n  Java语言提供了一种解决办法,就是synchronized块。

1.       使用同步块
2.       可以通过synchronized关键字将一个程序块声明为synchronized块。
              synchronized(object) {  //要互斥的语句  }
n  当一个线程执行这段代码时,它获得特定对象的所有权,即拥有该对象的锁。此时,如果有第二个线程对同一个对象也要执行这段代码时,它也试图获得该对象的所有权,但因该对象已被锁定,则第二个线程必须等待,直到锁被释放为止。
n  第一个线程执行完代码段后,自动释放锁,接下去第二个线程获得锁并可运行。

n  注意:
n  当维护所需要的同步特性时,要尽可能的缩小同步语句占用的时间,这样就能最小化被阻塞线程的等待时间。
n  线程之间的同步是针对线程间共享可变数据的情况,对于线程间共享不可变数据时,应将数据字段声明成final的。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马