• 多线程


      一、线程概述

        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类来创建线程的优缺点:

            优点:编写简单。

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

      

  • 相关阅读:
    centos 安装 TortoiseSVN svn 客户端
    linux 定时任务 日志记录
    centos6.5 安装PHP7.0支持nginx
    linux root 用户 定时任务添加
    composer 一些使用说明
    laravel cookie写入
    laravel composer 安装指定版本以及基本的配置
    mysql 删除重复记录语句
    linux php redis 扩展安装
    linux php 安装 memcache 扩展
  • 原文地址:https://www.cnblogs.com/fkrcode/p/6382663.html
Copyright © 2020-2023  润新知