zoukankan      html  css  js  c++  java
  • 多线程

      一、线程概述

        1.进程和线程的区别

          进程:进程是处于运行过程中的程序,并且具有一定的功能,是系统进行资源分配和调度的一个独立单位。

             主要特征:

            (1)独立性:系统中独立存在的实体,拥有自己的独立资源,拥有自己的私有地址空间,一个用户进程在不经过进程本身允许的情况下,

          不能访问其他进程的地址空间。

            (2)动态性:体现在进程和程序的区别。程序的静态的指令集合,而进程则是动态的指令集合,添加了时间。

            (3)并发性:多个进程在单个CUP上并发执行,多个进程之间不会相互影响。

                补充:并发:在同一时刻执行一条指令,但是多个进程指令被快速轮换执行,使得宏观上具有多个进程同时执行的效果。

                   并行:在同一时刻,有多条指令在多个处理器上同时执行。

          线程:进程的执行单位,在进程中独立的,并发的执行流,拥有自己的堆栈,自己的程序计数器和自己的局部变量,不拥有资源,与父进程的线程

          共享该进程的全部资源。

              主要特征:独立运行,抢占式执行。

          总结:操作系统可以同时执行多个任务,每个任务就是进程,进行也可以同时执行多个任务,每个任务就是线程。

        2.多线程的优势

          (1)进城之间不能共享内存,但是线程之间内存共享非常容易。

          (2)系统创建进程需要为该进程重新分配系统资源,但是创建线程代价小,因此开发效率较高。

          (3)Java语言内置了多线程的功能支持,而不是单纯的作为底层操作系统的调度方式,从而简化Java的多线程编程。

      二、线程的创建和启动

        1.创建线程的两三种方法

          (1)继承Thread类创建线程类

             通过继承该类创建并启动线程的步骤如下:

              a.定义Thread的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此run()方法称为线程执行体。

              b.创建Thread子类的实例,即创建了线程对象。

              c.调用线程对象的start()方法来启动线程。

            实例如下:

              

    /**
     * 
     * @author fengkuirui
     * @date 2017-02-09
     * 通过继承Thread类创建线程
     */
    public class FirstThread extends Thread {
        private int i;
        //重写run()方法
        @Override
        public void run(){
            for(;i<100;i++){
                //当线程继承Thread类时,直接实用this即可获得当前线程
                //Thread类的getName()返回当前线程的名字
                System.out.println(this.getName()+" "+i);
            }
        }
        public static void main(String[] args) {
            for(int i=0; i<100; i++){
                //调用Thread的currentThread()方法获取当前线程。
                System.out.println(Thread.currentThread().getName()+" "+i);
                if(i == 20){
                    //创建并启动第一个线程
                    new FirstThread().start();
                    //创建启动第二个线程
                    new FirstThread().start();
                }
            }
        }
    }

            运行结果如下:

              

            注意:通过继承Thread类的方法来创建线程类时,多个线程之间无法共享线程类的实例变量。

          (2)实现Runnable接口创建线程类

            (1)步骤

              a.定义Runnable接口的实现类,并重写该接口的run()方法。

              b.创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。

              c.调用start()方法启动该线程。

             (2)实例如下:

              

    /**
     * 
     * @author fengkuirui
     * @date 2017-02-09
     * 通过实现Runnable接口创建线程类
     */
    public class SecondThread implements Runnable{
        private int i;
        @Override
        public void run(){
            for(;i<100;i++){
                //输出当前线程的名字;
                System.out.println(Thread.currentThread().getName()+" "+i);
            }
        }
        public static void main(String[] args) {
            for(int i=0; i<100; i++){
                System.out.println(Thread.currentThread().getName()+" "+i);
                if(i == 20){
                    SecondThread st = new SecondThread();
                    //通过new Thread(target,name)方法创建新线程;
                    new Thread(st,"新线程1").start();
                    new Thread(st,"新线程2").start();
                }
            }
        }
    }

            (3)运行结果如下:

               

            注意:采用Runnable接口的方式创建的多个线程是可以共享线程类的实例变量。

          3.使用Callable和热Future创建线程

            (1)步骤

              a.创建Callable接口的实现类,并实现call()方法,该方法将作为线程执行体,并且该方法有返回值,再创建Callable实现类的实例。

              b.使用FutureTask类来包装Callable实现类对象,该FutureTask对象封装了该Callable实现类对象的call()方法的返回值。

              c.使用FutureTask对象作为Thread对象的target创建并启动线程。

              d.调用FutureTask对象的get()方法来实现线程类,并启动该线程。

            (2)实例如下:    

              

    import java.util.concurrent.Callable;
    import java.util.concurrent.FutureTask;
    
    /**
     * 
     * @author fengkuirui
     * @date 2017-02-09
     * 使用Callable和Future创建线程
     */
    public class ThridThread implements Callable<Integer>{
        
        
    
        @Override
        public Integer call() throws Exception {
            // TODO Auto-generated method stub
            int i=0;
            for(;i<100;i++){
                System.out.println(Thread.currentThread().getName()+" "+i);
            }
            //call()可以有返回值;
            return i;
        }
        public static void main(String[] args) {
            //创建Callable对象
            ThridThread rt = new ThridThread();
            //使用FutureTask来包装Callable对象
            FutureTask<Integer> task = new FutureTask<>(rt);
            for(int i=0;i<100;i++){
                System.out.println(Thread.currentThread().getName()+" "+i);
                if(i == 20){
                    //实质还是以Callable对象创建并启动线程;
                    new Thread(task,"有返回值的线程").start();
                }
            }
            try{
                //获取线程返回值
                System.out.println("子线程返回值: "+task.get());
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }

            运行结果如下:

              

              

        2.三种创建线程方式的区别

          (1)采用实现Runnable接口、Callable接口的方式创建线程的优缺点:

            a.线程类还可以继续继承其他类

            b.这种方式多线程共享一个target对象,所以非常适合多个相同的线程来处理同一份资源情况下,采用此种方式。

            缺点:编程稍微复杂,需要访问当前线程时,必须使用Thread.currentThread()方法。

          (2)采用继承Thread类来创建线程的优缺点:

            优点:编写简单。

            缺点:不能继承其他父类。

      

  • 相关阅读:
    HDU 4287 Intelligent IME 第37届ACM/ICPC天津赛区网络赛1010题 (水题)
    HDU 4267 A Simple Problem with Integers 第37届ACM/ICPC长春赛区网络赛1001题 (树状数组)
    HDU 4277 USACO ORZ 第37届ACM/ICPC长春赛区网络赛1011题(搜索)
    HDU 4099 Revenge of Fibonacci(字典树)
    HDU 2802 F(N)(简单题,找循环解)
    HDU 4282 A very hard mathematic problem 第37届ACM/ICPC长春赛区网络赛1005题 (暴力)
    HDU 4268 Alice and Bob 第37届ACM/ICPC长春赛区网络赛1002题 (贪心+multiset)
    HDU 3501 Calculation 2(欧拉函数的引申)
    HDU 4278 Faulty Odometer 第37届ACM/ICPC天津赛区网络赛1001题 (简单水题)
    HDU 4279 Number 第37届ACM/ICPC天津赛区网络赛1002题 (简单规律题)
  • 原文地址:https://www.cnblogs.com/fkrcode/p/6382663.html
Copyright © 2011-2022 走看看