• 实现Runnable 接口的类就是任务类(任务类不一定是实现Runnable接口的类)。
  1. 实现Runnable 接口,重写run()方法,run方法的返回值只能是 void 
  2. 任务类就是表示这个类要做什么,run是任务执行的入口,可以在run中完成任务也可以run调用其他方法完成任务。
  3. run 方法不会产生一个线程,必须把任务附着到线程上,线程才会执行任务。
  4. 有时run中通常存在某种形式的循环,一直等待着接收信息准备执行任务,多见于服务器。

2.Thread类

  • 构造器接收一个 Runnable 对象,当线程启动时会调用Runnable对象的run方法。
  1. Thread(Runnable target) 或者 传入一个string 作为线程的名字 Thread(Runnable target,String name) 
  2. 调用Thread对象的start( )方法启动线程,它会自动调用Runnable的run( )方法。
  3. start方法调用之后会迅速返回,执行main线程后面的代码,任务在启动的线程中继续执行。
  4. Thread对象和其他对象不同,Thread对象启动线程后,线程任务未完成之前,即run 方法未退出之前,垃圾回收器不会回收它。
  5. 常用的一个方法currentThread() 返回当前线程对象的引用。

3.Executor

  • 执行器,用来管理Thread对象,只有一个方法 execute(Runnable command) 执行提交的任务。
  • 这是一个异步执行框架可以控制线程的启动、执行和关闭,可以简化并发编程的操作。
  1. ExecutorService 线程池,该接口实现了 Executor 他知道如何根据恰当的上下文来执行Runnable对象,即根据线程环境,类型有顺序有条件的启动。
    1. 线程的创建代价非常高昂,最好是提前创建几个线程然后一直持有它,当执行完任务后不销毁而是重新放回线程池内等待执行下一个任务。
    2. 调用execute方法可以往线程池中添加任务,这些任务由线程池中的线程去执行。
    3. 调用 shutdown 之后可以阻止线程池再加入线程。
  2. Executors 是一个工具类,他可以产生ExecutorService对象和一些线程相关的其他对象。  
    1. newCachedThreadPool()  创建一个线程池  
    2. newFixedThreadPool(int i)  也可以创建一个固定线程数的程序池 
    3. newSingleThreadExecutor() 创建一个没有限制的队列池,放入的任务会排队执行,执行完一个任务才开始执行下一个任务。
  3. 线程池中的线程在可能情况下都会被复用,有个线程执行完一个任务会接着执行另一个任务。

4.从任务中产生返回值

  • Runnable 是执行工作的独立任务,他不能有任何返回值。
  • 如果想要任务完成时可以返回一个值,那么创建任务类时不用继承Runnable 接口 而是实现 Callable 接口。
  1. Callable<V> 和 Runnable 接口使用方法一样 V  call()执行任务 并且返回一个V类型的值
  2. ExecutorService  的 submit() 会返回一个Future 对象。
           <T> Future<T> submit(Callable<T> task)
            返回Callable任务执行结果的状态
            Future<?> submit(Runnable task)
            返回Runnable任务执行的状态
            <T> Future<T> submit(Runnable task, T result)
            返回Runnable任务执行的状态和 result 值 
  3. Future(接口)对象可以对Runnable和Callable任务进行取消、查询结果是否完成、获取结果。
  4. Future<V> 接口提供了一些方法用来对结果进行检测
            boolean cancel(boolean mayInterruptIfRunning)
            尝试取消执行此任务。
            V get()
            等待计算完成,然后检索其结果。
            V get(long timeout, TimeUnit unit)
            如果在规定时间内得到结果就立刻返回,超时抛出TimeoutException
            boolean isCancelled()
            如果此任务在正常完成之前被取消,则返回 trueboolean isDone()
            如果任务已完成返回true。  完成可能是由于正常终止,异常或取消

     调用get 之前最好 isDone判断一下,否则get将一直阻塞直到得到结果,或者使用超时get

      ExecutorService pool = Executors.newFixedThreadPool(1);
            Future<String> submit = pool.submit(new Callable<String>() {
                @Override
                public String call() throws InterruptedException {
                    Thread.sleep(5000);
                    return "时间到";
                }
            });
            pool.shutdown();
            System.out.println(new Date());
            System.out.println(submit.get());
            System.out.println(new Date());
    
    
    
    
    Wed Aug 22 17:31:02 CST 2018
    时间到
    Wed Aug 22 17:31:07 CST 2018
  5. FutureTask 类     构造器FutureTask(Callable<V> callable)     FutureTask(Runnable runnable, V result)   //Runnable 自身不返回结果,但可以设定返回一个V型值    
    1. FutureTask实现了 RunnableTask接口,RunnableTask接口又实现了Runnable,Future接口
    2. FutureTask 也是 Future接口的唯一实现
    3. 因为FutureTask 实现了Runnable接口 所以Thread可以通过启动FutureTask 启动Callable任务
        FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
                  @Override
                  public String call() throws InterruptedException {
                      Thread.sleep(5000);
                      return "时间到";
                  }
              });
              Thread thread = new Thread(futureTask);
              thread.start();
              System.out.println(new Date());
              System.out.println(futureTask.get());
              System.out.println(new Date());

       

5.休眠

  • 终止任务一段时间
  1. 可以使用TimeUtil.MILLISECONDS.sleep(1000); 休眠1000毫秒,也可以使用其他时间单位,或者使用Thread.sleep(1000),单位只能是毫秒
  2. 对sleep调用要抛出InterruptedException异常并且在run,call 方法中捕获,异常不能跨线程被捕获。

6.优先级

  • 线程的优先级将线程的重要性传递给了调度器,调度器
  • CPU 处理线程集的顺序不一定,但调度器倾向于让优先级高的线程执行。倾向于并不是一定
  1. 优先权不会导致死锁,优先权低的只是执行频率较低,并不是不执行。
  2. 绝大多时间里所有线程应该使用默认优先级,试图操纵线程的优先级让其先执行往往的不到效果,CPU不一定按优先级执行。
  3. Thread.currentThread().setPriority(int i) i 可以是1-10,未设置默认5,一般可以设置MAX_PRIORITY 最大10,或者MIN_PRIORITY最小1,NORM_PRIORITY中间5。
  4. 设置优先级一般在run 任务中第一句设置。
  5. Thread.yield() 建议具有相同优先级的其他线程执行,这只是一种建议,无法确保一定执行。

7.后台线程

  • daemon,  程序进程在运行的时候在后台提供一种通用服务的线程,并且不属于不可获取,程序可以没有后台线程,有时候需要后台线程提供一些服务。
  1. 一个程序(进程)在运行的时候如果所有非后台线程结束,该程序也就终止了,同时会杀死所有后台线程,不管后台线程是否执行完毕。
  2. 程序只要有一个非后台线程没有结束,程序就不会结束,main线程就是一个非后线程。
  3. 在一个线程调用start()之前调用 setDaemon(true) 可以设置该线程为后台线程。
  4. isDaemon() 判断一个线程是否为后台线程.
  5. 后台线程中创建的任线程都自动设置为后台线程。
  6. 所有非后台线程结束后,后台线程立刻被杀死即使有finally语句也不会执行

8.ThreadFactory

  • 该接口可以设置线程的属性,仅有一个方法Thread  newThread(Runnable r) 
  1. 实现ThreadFacory接口可以定制有由Executors创建的 线程池中的所有线程的属性
  2. 由Executors创建线程池的静态方法都被重载为一个可以接收ThreadFactory对象
     ExecutorService service = Executors.newCachedThreadPool(new DaemonThread(),);
            service.submit(new Prints());
    
    
    class DaemonThread implements ThreadFactory{
        @Override
        public Thread newThread(Runnable r) {
            Thread t  = new Thread(r);
            t.setDaemon(true);
            return t;
        }
    }

9.代码的变体

  • 一般都是任务类实现Runable接口,再传递给线程Thread启动,有时也可以用别的方法来替换这种方式。
  • 任务类不一定要从Runnable或者Callable接口实现,只要有run 或者call方法 并且线程能够执行这两个方法中,他们就统称任务类。
  1. 任务类直接从Thread继承:任务类直接继承Thread,在构造器中调用start(),当创建任务类对象时就启动了线程并执行任务
    lass SimpleThread extends Thread{
        SimpleThread(){
            start();
        }
    
        @Override
        public void run() {
            System.out.println("继承Thread的任务类");
        }
    }
  2. 任务类实现Runnable,内置Thread对象并传入任务类自己的引用this,并在构造器中启动start()
    class SelfManaged implements Runnable{
        SelfManaged(){
            thread.start();
        }
        Thread thread = new Thread(this);
    
        @Override
        public void run() {
            System.out.println("内置Thread的任务类");
        }
    }
  3. 注意1、2都是在构造器中启动线程,这意味着这个任务对象还未完全稳定线程就启动了,有可能另一个线程会访问这个不稳定的对象,这样就存在隐患。显示创建Thread就会存在这种问题,这也是优先使用Executor的原因。
  4. 可以通过内部类或者匿名内部类将线程代码隐藏在类中或者方法中。

10.加入一个线程

  1. A线程调用B线程的join()方法,则A线程会被挂起直到B线程执行被中断或者正常结束再继续执行A。
    class A extends Thread{
    
        Thread b;
        A(Thread b){
           this.b = b;
            start();
        }
    
        @Override
        public void run() {
            System.out.println("A线程启动");
            System.out.println("B线程加入");
            try {
                b.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("A线程结束");
        }
    }
    
    class B extends Thread{
    
       B(){
           start();
       }
    
        @Override
        public void run() {
            System.out.println("B线程执行");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("B结束执行");
        }
    }
    
    
    
       B b = new B();
          A a = new A(b);
    View Code

相关文章: