多线程

1.线程与进程关系:

  • 进程(process)
    • 所有运行中的任务通常对应一个进程。
    • 当一个程序进入内存运行时,即变成一个进程。
    • 进程是处于运行过程中的程序。
    • 进程是系统进行资源分配和调度的一个独立单位。
    • 独立性:每个进程都有自己的地址空间,在没有经过进程本身允许的情况下,进程不可直接访问其他进程的地址空间。
    • 动态性:程序是一个静态的指令集合,而进程是一正在系统中活动的指令集和,进程具有自己的声明周期和不同的状态。
    • 并发性:多个进程可在单个处理器上并发运行,多个进程之间不会互相影响。
  • 线程(thread)  
    • 线程也被称为轻量级进程,线程是进程的执行单元。
    • 线程是进程的组成部分,一个进程可以有多个线程。
    • 一个线程必须有一个父进程。
    • 线程可以拥有自己的堆栈、计数器和自己局部变量,但不能拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部系统资源。
    • 线程可以完成一定的任务,可以与其他线程共享父进程中的共享变量即部分环境,相互之间协同完成进程要完成的任务。
    • 线程是独立运行的。要确保线程不会妨碍同一进程里的其他线程。
    • 一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发运行。
  • 多线程存在于一个应用程序中,让一个应用程序中可以有多个执行部分同时执行,但操作系统无需讲多个线程看作多个独立的应用,对多线程实现调度和管理以及资源分配。线程的调度和管理有进程本身负责完成。
  • 一个程序运行后至少有一个进程,一个进程中可以包含多个线程,但至少要包含一个线程。

 2.线程的优势

  • 进程之间不能共享内存,但线程之间共享内存非常容易
  • 系统创建进程时需要为该进程重新分配系统资源,但创建线程则代价小的多,因此使用多线程来实现多任务并发比多进程的效率高。

3.线程的创建

  • 继承Thread类创建线程类
  • ①定义Thread类的子类,并重写该类的run()方法,该run()方法的方法提就是线程
      需要完成的任务,因此run()方法成为线程的执行体。
    ②创建Thread子类的实例,及创建了线程对象。
    ③调用线程对象的start()方法来启动线程。
    public class FirstThread extends Thread
    {
        private int i ;
        // 重写run方法,run方法的方法体就是线程执行体
        public void run()
        {
            for ( ; i < 100 ; i++ )
            {
                // 当线程类继承Thread类时,直接使用this即可获取当前线程
                // Thread对象的getName()返回当前该线程的名字
                // 因此可以直接调用getName()方法返回当前线程的名
                System.out.println(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();
                }
            }
        }
    }

     

 

  • 实现Runnable接口创建线程类
  • ①定义Runnable接口的实现类
    ②创建Runnable实现类的实例
    ③调用线程对象的start()方法启动多线程
    public class SecondThread implements Runnable
    {
        private int i ;
        // run方法同样是线程执行体
        public void run()
        {
            for ( ; i < 100 ; i++ )
            {
                // 当线程类实现Runnable接口时,
                // 如果想获取当前线程,只能用Thread.currentThread()方法。
                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();
                }
            }
        }
    }

     

  • 使用Callable和Future创建线程

 

  • ①创建Callable接口的实现类,并实现call()方法,将call()方法作为线程执行体,
    且该call()方法有返回值,在创建Callable实现类的实例。java8开始可使用Lambda表达式创建Callable对象。
    public class ThirdThread { public static void main(String[] args) { // 创建Callable对象 ThirdThread rt = new ThirdThread(); // 先使用Lambda表达式创建Callable<Integer>对象 // 使用FutureTask来包装Callable对象 FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> { int i = 0; for ( ; i < 100 ; i++ ) { System.out.println(Thread.currentThread().getName() + " 的循环变量i的值:" + i); } // call()方法可以有返回值 return i; }); for (int i = 0 ; i < 100 ; i++) { System.out.println(Thread.currentThread().getName() + " 的循环变量i的值:" + i); if (i == 20) { // 实质还是以Callable对象来创建、并启动线程 new Thread(task , "有返回值的线程").start(); } } try { // 获取线程返回值 System.out.println("子线程的返回值:" + task.get()); } catch (Exception ex) { ex.printStackTrace(); } } }

     

 

 

4.创建线程三种方式的比较

**实现Runnable接口与实现Callable接口方式基本相同,试试Calllable接口里定义的方法有返回值,可以声明抛出异常。

  • 创建线程一般推荐使用Runnable几口、Callable接口的方式。

 

 

 

 

 

posted @ 2016-06-02 14:15  芬乐  阅读(207)  评论(0编辑  收藏  举报