并发编程与进程和多线程的关系及如何创建多线程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37358860/article/details/80027204

一. 进程和线程

    几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程,当一个
 程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程.一定的独立功能,进程是系统进行资源分配
 和调度的一个独立单位.

进程的特点:

  1. 独立性: 进程是系统中独立存在的实体,它可以拥有自己独立的资源,每一个进程都拥有自己私有的地址空间,在没有经过进程自己本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间.
  2. 动态性: 进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合,即进程中加入了时间概念.进程具有自己的声明周期和各种不同的状态,这些概念在程序中都是不具备的.
  3. 并发性: 多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响.

线程的特点:

  1. 线程是进程的组成部分: 一个进程可以拥有多个线程,一个线程必须有一个父进程.线程可以拥有自己的堆栈,自己的程序计数器和自己的局部变量,单不拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部资源
  2. 线程可以完成一定的任务: 线程可以与其他线程共享父进程中的共享变量及部分环境,相互之间协同来完成进程所要完成的任务.
  3. 一个线程可以创建和撤销另一个线程,同一个进程中的多个线程可以并发执行.

多线程编程的几个优先:

  1. 进程之间不能共享内存,但同一个进程中的线程之间共享内存非常容易
  2. 系统创建进程时,需要为该进程重新分配系统资源,但创建线程则代价小的多,因此使用多线程来实现多任务并发比多进程的效率高
  3. Java语言内置了多线程功能支持,而不是单纯地作为地城操作系统的调度方式,从而简化了Java的多线程编程

二. 并发编程

      并发编程使我们可以将程序划分为多个分离的,独立运行的任务.通过使用多线程机制,这些独立任务中的每一个都
  将由执行线程来驱动.而顺序编程,即程序中所有的事物在任意时刻都只能执行一个步骤.并发编程可以使程序执行的速
  度得到极大的提高,或者为设计某些类型的程序提供更易用的模型.
  • 并发的多面性: 并发编程令人困惑的一个主要原因是: 使用并发时需要解决的问题有多个,而实现并发方式也有多种,并且这两者之间没有明显的映射关系(而且通常只具有模糊的界限).因此,我们必须理解所有的这些问题和特例,以便有效的使用并发.

  • 用并解决的问题大体上可以分为”速度”和”设计可管理性”两种

  • 更快的执行: 如果你想要一个程序运行的更快,那么可以将其断开为多个片段,在单独的处理器上运行每个片段.并发是用于多处理器编程的基本工具.

  • 改进代码设计: 在单CPU机器上使用多任务的程序在任意时刻仍旧只在执行一项工作,因此从理论上讲,肯定可以不用任何任务而编写出相同的程序.但是,并发提供了一个重要的组织结构上的好处:你的程序设计可以极大的简化.某些类型的问题,例如仿真,没有并发的支持,是很难解决的.

三. 线程的创建和启动

通过继承Thread类来创建线程
package com.laolang.thread;
/**
 * 标题: Thread.java
 * 路径: com.laolang.thread
 * 描述: 通过继承Thread 类来创建线程类
 * 版本: @version V1.0
 */
public class FirstThread extends Thread{
    private int i;
    //重写run()方法,run()方法的方法体就是线程执行体
    public void run(){
        for ( i = 0; 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().getName()方法获取当前线程
            System.out.println(Thread.currentThread().getName()+"  "+i);
            //当i等于20时,创建并启动两个FirstThread线程
            if(i==20){
                //创建并启动第一个线程
                new FirstThread().start();;
                //创建并启动第二个线程
                new FirstThread().start();
            }
        }
    }
}
通过实现Runnable接口来创建线程,在这里我们可以把实现Runnable接口的来当做一个需要执行的任务,而new Thread()
方法是将这个任务交个一个线程来管理.否则实现Runnable结构的这个类中的run()方法不会产生任何内在的线程的能力.想
要实现线程行为,就必须显示的将它附着到线程上.
package com.laolang.thread;
/**
 * 标题: SecondThread.java
 * 路径: com.laolang.thread
 * 描述: 实现Runnable接口来创建并启动线程
 * 版本: @version V1.0
 */
public class SecondThread implements Runnable {
    private int i;
    //run()方法同样是线程执行体
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; 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++) {
            //调用Thread的currentThread().getName()方法获取当前线程
            System.out.println(Thread.currentThread().getName()+"  "+i);
            //当i等于20时,创建并启动两个FirstThread线程
            if(i==20){
                //创建并启动第一个线程
                new Thread(new SecondThread(),"线程1").start();
                //创建并启动第二个线程
                new Thread(new SecondThread(),"线程2").start();
            }
        }
    }

}
使用Executor执行器管理Thread对象,在下面示例中,CachedThreadPool将为每个任务都创建一个线程.注意,
ExecutorService对象是使用静态的Executor方法创建的,这个方法可以确定其Executor的类型
package com.laolang.thread;
/**
 * 标题: ThirdThread.java
 * 路径: com.laolang.thread
 * 描述: 实现Runnable接口,并实现run()方法
 * 版本: @version V1.0
 */
public class ThirdThread implements Runnable{
    protected int countDown = 10;//默认
    private static int taskCount = 0;
    private final int id = taskCount++;
    public ThirdThread() {
        // TODO Auto-generated constructor stub
    }
    public ThirdThread(int countDown) {
        // TODO Auto-generated constructor stub
        this.countDown = countDown;
    }

    public String status(){
        return "#" + id + " ("+(countDown > 0 ? countDown : "ThirdThread") + "), ";
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while (countDown-- > 0 ) {
            System.out.println(status());
            /**
             * 对调度程序的提示,当前线程愿意放弃当前使用的处理器。调度器可以忽略这个提示。Yield是一种启发式的尝试,
             * 以改进在其他情况下会过度使用CPU的线程之间的相对进展。它的使用应该与详细的分析和基准测试相结合,以确保它实际上有预期的效果。
             * 使用这种方法是不合适的。它可能对调试或测试的目的很有用,在那里它可以帮助复制由于竞争条件而产生的错误。
             * 在设计类似java.util.concurrent中的并发控制结构时,它可能也很有用。锁方案。
             * 
             * 我们在这里使用,是为了看到线程之间相互切换的输出.
             */
            Thread.yield();
        }
    }
}
package com.laolang.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * 标题: CachedThreadPool.java
 * 路径: com.laolang.thread
 * 描述: 使用Executor管理Thread
 *        使用Executor执行器管理Thread对象,在下面示例中,CachedThreadPool将为每个任务都创建一个线程.
 *        注意,ExecutorService对象是使用静态的Executor方法创建的,这个方法可以确定其Executor的类型
 * 版本: @version V1.0
 */
public class CachedThreadPool {
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            exec.execute(new ThirdThread());
        }
        exec.shutdown();
    }
}
Runnable是执行工作的独立任务,但是它不返回任何值,如果我们希望任务执行完之后可以返回一个值,那么我们可以实现
Callable接口,Callable是一种具有类型参数的泛型,它的类型参数表示的从方法call()(而不是run())中返回的值,并
且必须使用ExecutorService.submit()方法调用它
package com.laolang.thread;

import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class FourthThread implements Callable{
    private int id;
    public  FourthThread(int id) {
        // TODO Auto-generated constructor stub
        this.id = id;
    }
    //相当于Runnable中的run()方法
    @Override
    public Object call() throws Exception {
        // TODO Auto-generated method stub
        return "result of FourthThread "+ id;
    }

    public static void main(String[] args) {
        //创建Executor对象来管理线程
        ExecutorService exec = Executors.newCachedThreadPool();
        //创建线程返回值的集合
        ArrayList<Future<String>> results = new ArrayList<Future<String>>();
        for (int i = 0; i < 10; i++) {
            //submit()方法可以返回Future对象,exec.submit(new FourthThread(i))是将new FourthThread(i)对象中call()放到一个线程上执行
            results.add( exec.submit(new FourthThread(i)));
        }
        //遍历results
        for (Future<String> future : results) {
            try {
                System.out.println(future.get());//future.get()方法,得到线程执行的返回值
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally{
                exec.shutdown();
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_37358860/article/details/80027204