JAVA多线程

来源:互联网 发布:内网端口号干嘛用 编辑:程序博客网 时间:2024/06/04 15:25

JAVA多线程

synchronized和Lock

      Lock是一个接口,它位于Java 5.0新增的java.utils.concurrent包的子包locks中。concurrent包及其子包中的类都是用来处理多线程编程的。实现Lock接口的类具有与synchronized关键字同样的功能,但是它更加强大一些。java.utils.concurrent.locks.ReentrantLock是较常用的实现了Lock接口的类。下面是ReentrantLock类的一个应用实例:

Java代码

  1. private Lock lock = new ReentrantLock();   
  2.   
  3. public void testLock() {   
  4.     // 锁定对象   
  5.      lock.lock();   
  6.     try {   
  7.         // do something   
  8.      } finally {   
  9.         // 释放对对象的锁定  
  10.          lock.unlock();   
  11.      }   
  12. }  

private Lock lock = newReentrantLock();

 

public void testLock() {

 // 锁定对象

 lock.lock();

 try {

  // do something

 } finally {

  // 释放对对象的锁定

  lock.unlock();

 }

}


lock()方法用于锁定对象,unlock()方法用于释放对对象的锁定,他们都是在Lock接口中定义的方法。位于这两个方法之间的代码在被执行时,效果等同于被放在synchronized同步块中。一般用法是将需要在lock()和unlock()方法之间执行的代码放在try{}块中,并且在finally{}块中调用unlock()方法,这样就可以保证即使在执行代码抛出异常的情况下,对象的锁也总是会被释放,否则的话就会为死锁的产生增加可能。
      使用synchronized关键字实现的同步,会把一个对象的所有同步方法和同步块看做一个整体,只要有一个被某个线程调用了,其他的就无法被别的线程执行,即使这些方法或同步块与被调用的代码之间没有任何逻辑关系,这显然降低了程序的运行效率。而使用Lock就能够很好地解决这个问题。我们可以把一个对象中按照逻辑关系把需要同步的方法或代码进行分组,为每个组创建一个Lock类型的对象,对实现同步。那么,当一个同步块被执行时,这个线程只会锁定与当前运行代码相关的其他代码最小集合,而并不影响其他线程对其余同步代码的调用执行。

关于死锁

死锁就是一个进程中的每个线程都在等待这个进程中的其他线程释放所占用的资源,从而导致所有线程都无法继续执行的情况。死锁是多线程编程中一个隐藏的陷阱,它经常发生在多个线程共用资源的时候。在实际开发中,死锁一般隐藏的较深,不容易被发现,一旦死锁现象发生,就必然会导致程序的瘫痪。因此必须避免它的发生。

程序中必须同时满足以下四个条件才会引发死锁:

  1. 互斥(Mutual exclusion):线程所使用的资源中至少有一个是不能共享的,它在同一时刻只能由一个线程使用。
  2. 持有与等待(Hold and wait):至少有一个线程已经持有了资源,并且正在等待获取其他的线程所持有的资源。
  3. 非抢占式(No pre-emption):如果一个线程已经持有了某个资源,那么在这个线程释放这个资源之前,别的线程不能把它抢夺过去使用。
  4. 循环等待(Circular wait):假设有N个线程在运行,第一个线程持有了一个资源,并且正在等待获取第二个线程持有的资源,而第二个线程正在等待获取第三个线程持有的资源,依此类推……第N个线程正在等待获取第一个线程持有的资源,由此形成一个循环等待。

线程池

线程池就像数据库连接池一样,是一个对象池。所有的对象池都有一个共同的目的,那就是为了提高对象的使用率,从而达到提高程序效率的目的。比如对于Servlet,它被设计为多线程的(如果它是单线程的,你就可以想象,当1000个人同时请求一个网页时,在第一个人获得请求结果之前,其它999个人都在郁闷地等待),如果为每个用户的每一次请求都创建一个新的线程对象来运行的话,系统就会在创建线程和销毁线程上耗费很大的开销,大大降低系统的效率。因此,Servlet多线程机制背后有一个线程池在支持,线程池在初始化初期就创建了一定数量的线程对象,通过提高对这些对象的利用率,避免高频率地创建对象,从而达到提高程序的效率的目的。
      下面实现一个最简单的线程池,从中理解它的实现原理。为此我们定义了四个类,它们的用途及具体实现如下:
[list=1]

·  Task(任务):这是个代表任务的抽象类,其中定义了一个deal()方法,继承Task抽象类的子类需要实现这个方法,并把这个任务需要完成的具体工作在deal()方法编码实现。线程池中的线程之所以被创建,就是为了执行各种各样数量繁多的任务的,为了方便线程对任务的处理,我们需要用Task抽象类来保证任务的具体工作统一放在deal()方法里来完成,这样也使代码更加规范。
Task的定义如下:

Java代码

  1. public abstract class Task {   
  2.     public enum State {   
  3.         /* 新建 */NEW,/* 执行中 */RUNNING,/* 已完成 */FINISHED   
  4.      }   
  5.   
  6.     // 任务状态   
  7.     private State state = State.NEW;   
  8.   
  9.     public void setState(State state) {   
  10.         this.state = state;   
  11.      }   
  12.   
  13.     public State getState() {   
  14.         return state;   
  15.      }   
  16.   
  17.     public abstract void deal();   
  18. }  

public abstract class Task {

 public enum State {

  /* 新建 */NEW, /* 执行中 */RUNNING, /* 已完成 */FINISHED

 }

 

 // 任务状态

 private State state = State.NEW;

 

 public void setState(State state) {

  this.state = state;

 }

 

 public State getState() {

  return state;

 }

 

 public abstract void deal();

}

·  TaskQueue(任务队列):在同一时刻,可能有很多任务需要执行,而程序在同一时刻只能执行一定数量的任务,当需要执行的任务数超过了程序所能承受的任务数时怎么办呢?这就有了先执行哪些任务,后执行哪些任务的规则。TaskQueue类就定义了这些规则中的一种,它采用的是FIFO(先进先出,英文名是First In First Out)的方式,也就是按照任务到达的先后顺序执行。
TaskQueue类的定义如下:

Java代码

  1. import java.util.Iterator;   
  2. import java.util.LinkedList;   
  3. import java.util.List;   
  4.   
  5. public class TaskQueue {   
  6.     private List<Task> queue =new LinkedList<Task>();   
  7.   
  8.     // 添加一项任务   
  9.     public synchronized void addTask(Task task) {   
  10.         if (task != null) {   
  11.              queue.add(task);   
  12.          }   
  13.      }   
  14.   
  15.     // 完成任务后将它从任务队列中删除  
  16.     public synchronized void finishTask(Task task) {   
  17.         if (task != null) {   
  18.              task.setState(Task.State.FINISHED);   
  19.              queue.remove(task);   
  20.          }   
  21.      }   
  22.   
  23.     // 取得一项待执行任务  
  24.     public synchronized Task getTask() {   
  25.          Iterator<Task> it = queue.iterator();   
  26.          Task task;   
  27.         while (it.hasNext()) {   
  28.              task = it.next();   
  29.             // 寻找一个新建的任务  
  30.             if (Task.State.NEW.equals(task.getState())) {   
  31.                 // 把任务状态置为运行中  
  32.                  task.setState(Task.State.RUNNING);   
  33.                 return task;   
  34.              }   
  35.          }   
  36.         return null;   
  37.      }   
  38. }  

import java.util.Iterator;

import java.util.LinkedList;

import java.util.List;

public class TaskQueue {

 private List<Task> queue = newLinkedList<Task>();

 

 // 添加一项任务

 public synchronized void addTask(Task task) {

  if (task != null) {

   queue.add(task);

  }

 }

 // 完成任务后将它从任务队列中删除

 public synchronized void finishTask(Task task){

  if (task != null) {

   task.setState(Task.State.FINISHED);

   queue.remove(task);

  }

 }

 // 取得一项待执行任务

 public synchronized Task getTask() {

  Iterator<Task> it = queue.iterator();

  Task task;

  while (it.hasNext()) {

   task = it.next();

   // 寻找一个新建的任务

   if (Task.State.NEW.equals(task.getState())){

    // 把任务状态置为运行中

    task.setState(Task.State.RUNNING);

    return task;

   }

  }

  return null;

 }

}

addTask(Task task)方法用于当一个新的任务到达时,将它添加到任务队列中。这里使用了LinkedList类来保存任务到达的先后顺序。finishTask(Tasktask)方法用于任务被执行完毕时,将它从任务队列中清除出去。getTask()方法用于取得当前要执行的任务。

·  TaskThread(执行任务的线程):它继承自Thread类,专门用于执行任务队列中的待执行任务。

Java代码

  1. public class TaskThread extends Thread {   
  2.     // 该线程所属的线程池  
  3.     private ThreadPoolService service;   
  4.   
  5.     public TaskThread(ThreadPoolService tps) {   
  6.          service = tps;   
  7.      }   
  8.   
  9.     public void run() {   
  10.         // 在线程池运行的状态下执行任务队列中的任务  
  11.         while (service.isRunning()) {   
  12.              TaskQueue queue = service.getTaskQueue();   
  13.              Task task = queue.getTask();   
  14.             if (task != null) {   
  15.                  task.deal();   
  16.              }   
  17.              queue.finishTask(task);   
  18.          }   
  19.      }   
  20. }  

 

原创粉丝点击