Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / Java并发操作——基本的线程机制

1)定义任务          线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供(有的地方比如Swing2中经常将其叫做可运行对象)。要想定义任务,只需要实现Runnable接口并编写run()方法,使得该任务执行命令。 但是此时呢,这个run()方法跟一个普通方法一样,并没有什么特殊的地方,不会产生任何内在的线程能力。要实现线程行为,我们必须在使用的时候显示的将一个任务附着到现场上。2)Thread类          要想Runnable对象要想具有线程行为,传统的方式就是把它提交给一个Thread构造器。然后调用Thread类的start()方法为该线程执行必须的初始化操作,继而调用Runnable的run()方法。      下面的代码简单演示Thread的用法 public class LiftOff implements Runnable {
   
    public int countDown =10;
   
    private static int taskCount = 0;
   
    private final int id = taskCount++;
   
    public LiftOff() {
        System.out.println("默认构造函数");
    }    public LiftOff(int countDown) {
        System.out.println("非默认的构造函数");
        this.countDown = countDown;
    }
   
    public String getStatus() {
        return "#" + id + "(" + (countDown > 0 ? countDown : "LiftOff") + ").";
    }
   
    @Override
    public void run() {
        while(countDown-->0) {
            System.out.print(getStatus());
            Thread.yield();
        }
    }}  import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadTestWithExecutor {    private static final int count = 5;
   
    /**
   * @param args
   */
    public static void main(String[] args) {
        //1.什么都不加。
        for(int i=0;i<count;i++) {
         Thread t = new Thread(new LiftOff());
         t.start();
     }
        System.out.println("执行完毕!");
    }} 第一次执行结果 默认构造函数
默认构造函数
默认构造函数
默认构造函数
默认构造函数
执行完毕!
#0(9).#0(8).#0(7).#1(9).#3(9).#2(9).#4(9).#0(6).#2(8).#4(8).#0(5).#2(7).#4(7).#0(4).#2(6).#4(6).#3(8).#2(5).#4(5).#2(4).#2(3).#4(4).#1(8).#3(7).#2(2).#1(7).#3(6).#2(1).#1(6).#3(5).#0(3).#2(LiftOff).#1(5).#3(4).#4(3).#1(4).#3(3).#0(2).#4(2).#1(3).#3(2).#0(1).#3(1).#1(2).#4(1).#1(1).#3(LiftOff).#0(LiftOff).#1(LiftOff).#4(LiftOff) 第二次执行结果 默认构造函数
默认构造函数
默认构造函数
默认构造函数
默认构造函数
执行完毕!
#1(9).#3(9).#1(8).#3(8).#1(7).#3(7).#1(6).#3(6).#1(5).#3(5).#1(4).#3(4).#1(3).#3(3).#1(2).#3(2).#1(1).#3(1).#1(LiftOff).#3(LiftOff).#0(9).#2(9).#4(9).#0(8).#2(8).#4(8).#0(7).#2(7).#4(7).#0(6).#2(6).#4(6).#0(5).#2(5).#4(5).#0(4).#2(4).#4(4).#0(3).#2(3).#4(3).#0(2).#2(2).#4(2).#0(1).#2(1).#4(1).#0(LiftOff).#2(LiftOff).#4(LiftOff). 从上述两次的执行结果中,我们可以得到以下结论:   (1)多线程的执行不是按照顺序执行的,各个线程之间相互交叉。
       #0(9).#0(8).#0(7).#1(9).#3(9).#2(9) 说明可Runnable0还没执行完,Runnable2 就执行了。   (2)start()方法看起来是产生了一个对长期运行方法的调用(即run方法),但是从实际的输出情况来看,start()方法迅速的返回了,因为“执行完毕”在run()方法执行完毕之前就已经输出了。实际上,我们产生的是对Runnable.run()方法的调用,并且这个方法还没有完成,但是因为这个方法是由不同的线程执行的,因此我们仍然可以执行main()线程中的其他操作(当然这种能力并不局限于main()线程,任何线程都可以启动另一个线程)。因此这时候程序会同时运行两个方法、    (3)比较两次执行结果可以发现,两次执行的结果不一样。这是因为线程调度机制是非确定的。 3)使用Exexutor       在Java SE5的java.util.concurrent包中的执行器(Executor)将为我们管理Thread对象,从而简化了并发编程。   下面的代码就列举了几种不同Executor的执行情况: public class LiftOff implements Runnable {
   
    public int countDown =10;
   
    private static int taskCount = 0;
   
    private final int id = taskCount++;
   
    public LiftOff() {
        System.out.println("默认构造函数");
    }    public LiftOff(int countDown) {
        System.out.println("非默认的构造函数");
        this.countDown = countDown;
    }
   
    public String getStatus() {
        return "#" + Thread.currentThread().getId() + "(" + (countDown > 0 ? countDown : "LiftOff") + ").";
    }
   
    @Override
    public void run() {
        while(countDown-->0) {
            System.out.print(getStatus());
            Thread.yield();
        }
    }}  import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/**
* CachedThreadPool
*/
public class ThreadTestWithExecutor {   
    private static final int count = 5;
   
    /**
   * @param args
   */
    public static void main(String[] args) {
       
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i=0;i<count;i++) {
            exec.execute(new LiftOff());
        }
        exec.shutdown();
          //3.使用FixThreadPool
            ExecutorService exec2 = Executors.newFixedThreadPool(3);
            for(int i=0;i<count;i++) {
               exec2.execute(new LiftOff());
              }
         exec2.shutdown();          //4.SingleThreadExecutor
         ExecutorService exec3 = Executors.newSingleThreadExecutor();
         for(int i=0;i<count;i++) {
              exec3.execute(new LiftOff());
              }
            exec.shutdown();
        System.out.println("执行完毕!");      }} 这几段代码,都很简单,但是有几点需要说明    1)shutdown()方法的调用可以防止新任务被提交给这个Executor,当前线程(在上述代码中就是驱动main()的线程)将继续运行在shutdown()被调用之前提交的所有任务。换句说,虽然是shutdown了,但是当前在执行器中的线程仍然会继续执行。    2)FixedThreadPool可以一次性预先执行代价高昂的线程分配(因而就可以限制线程的数量了)。这样会节省时间,因为你不用为每个任务都固定的付出创建线程的时间(记住,虽然每次new了一个Runnable对象,但是并不是每个Runnable对象都会new一次Thread.),直接从线程池中取线程即可。 但是,我们一定要记住一点,在任何线程池中,现有线程在可能的情况下, 都会被复用。 3)SingleThreadExecutor就像是线程数量为1的FixedThreadPool。这时候如果向其提交了多个任务,这些任务就会排队。每个任务都会在下一个任务开始之前运行结束。所有的任务将使用相同的线程。大话设计模式(带目录完整版) PDF+源代码 http://www.linuxidc.com/Linux/2014-08/105152.htmJava中介者设计模式 http://www.linuxidc.com/Linux/2014-07/104319.htmJava 设计模式之模板方法开发中应用 http://www.linuxidc.com/Linux/2014-07/104318.htm设计模式之 Java 中的单例模式(Singleton) http://www.linuxidc.com/Linux/2014-06/103542.htm本文永久更新链接地址:http://www.linuxidc.com/Linux/2014-10/107582.htm