zoukankan      html  css  js  c++  java
  • Java多线程(一) 基础以及线程的创建

    线程与进程的区别

    线程

      线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。

      线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

        在Java Web中要注意,线程是JVM级别的,在不停止的情况下,跟JVM共同消亡,就是说如果一个Web服务启动了多个Web应用,某个Web应用启动了某个线 程,如果关闭这个Web应用,线程并不会关闭,因为JVM还在运行,所以别忘了设置Web应用关闭时停止线程。

    线程对象是可以产生线程的对象。比如在Java平台中Thread对象,Runnable对象。线程,是指正在执行的一个指点令序列。在java平台上是指从一个线程对象的start()开始,运行run方法体中的那一段相对独立的过程。相比于多进程,多线程的优势有:

        (1)进程之间不能共享数据,线程可以;

        (2)系统创建进程需要为该进程重新分配系统资源,故创建线程代价比较小;

        (3)Java语言内置了多线程功能支持,简化了java多线程编程。

    进程

      进程是操作系统结构的基础;是一次程序的执行;是一个程序及其数据在处理机上顺序执行时所发生的活动。操作系统中,几乎所有运行中的任务对应一条进程(Process)。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。描述进程的有一句话非常经典——进程是系统进行资源分配和调度的一个独立单位。

      进程是系统中独立存在的实体,拥有自己独立的资源,拥有自己私有的地址空间进程的实质,就是程序在多道程序系统中的一次执行过程,它是动态产生,动态消亡的,具有自己的生命周期和各种不同的状态。进程具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进。 

    (注意,并发性(concurrency)和并行性(parallel)是不同的。并行指的是同一时刻,多个指令在多台处理器上同时运行。并发指的是同一时刻只能有一条指令执行,但多个进程指令被被快速轮换执行,看起来就好像多个指令同时执行一样。)

      进程由程序数据进程控制块三部分组成。

    Java多线程总结

    一.创建线程与启动

    1,继承Thread类创建,代码如下

    2,定义一个继承Thread类的子类,并重写该类的run();方法

    3,创建Thread子类的实例,即创建了线程对象

    调用该线对象的start()方法启动线程。

    public class DuoXianCheng extends  Thread{
        private  String name;
    
        public DuoXianCheng(){
        }
        public DuoXianCheng(String name){
            this.name=name;
        }
    //  创建线程和启动
    // 1通过继承Thread类创建线程类
    //  定义一个继承Thread类的子类,并重写该类的run()方法;
    //  创建Thread子类的实例,即创建了线程对象;
    //  调用该线程对象的start()方法启动线程。
        public void run(){
    
            for (int o=1;o<5; o++){
                System.out.println(name+"运行"+o);
            }
        }
        public static void main(String[] args) {
            DuoXianCheng duoXianCheng1 = new DuoXianCheng("A");
            DuoXianCheng duoXianCheng2 = new DuoXianCheng("B");
            //第三步启动线程
            duoXianCheng1.start();
            duoXianCheng2.start();
        }
    }

    结果:(多次运行结果可能不一样)

    二.实现Runnable接口创建线程类

    定义一个Runnable的实现类,并重写该接口的run()方法;

    创建Runnable实现类的实例,并以此实例作为Thread的target对象,

    即该Thread对象才是真正的线程对像

    通过实现Runnable接口创建线程类的具体步骤和具体代码如下:

    public class SomeThreads implements Runnable {
        private  String name;
        public  SomeThreads(){
        }
        public SomeThreads(String name){
            this.name = name;
        }
        //   实现Runnable接口创建线程类
    //   通过实现Runnable接口创建线程类
    //  定义Runnable接口类的实现,并重写run()方法;
    //定义Runnable实现类的实例,并以此实例作为Thread的的target对象,即该Thread对象真正的线程对象
        @Override
        public void run() {
        for (int i=0;i<5;i++){
            System.out.println(name +"运行"+i);
        }
        }
    
        public static void main(String[] args) {
            SomeThreads someThreads1 = new SomeThreads("线程是s1");
            Thread thread1 = new Thread(someThreads1);
            SomeThreads someThreads2 = new SomeThreads("线程s2");
            Thread thread2 =new Thread(someThreads2);
            thread1.start();
            thread2.start();
        }

    结果是:(每次运行的结果可能不一样)

    创建多线程是选择实现Runnable接口还是继承Thread?

    看Thread源码发现Thread也是实现Runnable接口的:

    Thread中的run方法调用的是Runnable接口的run方法,其实Thread和Runnable都实现了run方法,这种操作模式就是代理模式。

    Thread和Runnable的区别

    类继承Thread,则不适合资源共享。但是实现Runnable接口,就很容易实现资源共享。

    public class Hello extends Thread{
        private  int count = 5;  //数量为5
        public  void run(){
            for (int i =0;i<6;i++){
                if (count>0){
                    System.out.println(count--+"sount");
                }
            }
        }
        public static void main(String[] args) {
            Hello hello1 = new Hello();
            Hello hello2 = new Hello();
            hello1.start();
            hello2.start();
        }
    }

    运行结果:

     可以看到,两个线程并没有进行资源共享,而是每个线程的count都等于5,接下来看

    实现Runnable接口

     class World implements Runnable{
        private int count = 5; //剩余餐数为五
        @Override
        public void run() {
            for (int i =0;i<6;i++){
                if (this.count>0){
                    System.out.println(Thread.currentThread().getName()+"剩余餐数"+this.count--);
                }
            }
        }
    }
    public class sun{
        public static void main(String[] args) {
            World world1  = new World();
            new Thread(world1,"1号出餐口").start();
            new Thread(world1,"2号出餐口").start();
    
        }
    }

    运行结果:

     可以看出来,继承Thread没有进行资源共享,而实现Runnable进行了资源共享

    总结一下二者:

    1,使用继承Thread类的方式创建多线程

    (1)优势

    编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获取当前线程

    (2)劣势

    线程类已经继承了Thread类,所以不能在继承其他父类。(有单继承的局限性)

    创建多线程,每个任务有成员变量时不共享,必须加static才能做到共享

    2.使用实现Runnable类的方式创建多线程

    (1)优势

    避免了单继承的局限性,多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形

    (2)劣势

    比较复杂,访问线程必须使用Thread.currentThread()方法,无返回值。

    3.使用实现Callable接口的创建多线程

    (1)优势

    有返回值,避免了单继承的局限性,多个继承可以共享一个target对象,非常适合多线程处理同一份资源的情形。

    (2)劣势

    比较复杂,访问线程必须使用Thread.currentThread()方法。

    实现Runnable接口比继承Thread类所具有的优势:

    1.多个相同程序代码线程去处理同一个资源

    2.可以避免Java中单继承的限制

    3.增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。

    所以尽量使用实现Runnable接口

    Runnable和Callable的区别

    1)Callable规定(重写)的方法是call(),Runnable规定(重写)的方法是run()。
    2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
    3)call方法可以抛出异常,run方法不可以。
    4)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的
    完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果future.get()

    三 , 通过Callable和Future创建线程

    实现步骤如下:

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

    2.创建Callable实现类的实例,使用FutrueTask类进行包装Callable对象,FutrueTask对象封装了Callable对象的call()方法的返回值

    3.使用FutrueTask对象作为Thread对象的target创建并启动新线程

    4.调用FutrueTask对象的Get()方法获取到子线程执行结束后的返回值。

    代码如下:

    //创建一个类,实现Callable接口,并实现call()方法
    public class ImplCallable01 implements Callable {
        @Override
        public Object call() throws Exception {
            int u = 0;
            for (;u<10;u++){
                System.out.println(Thread.currentThread().getName()+" " +u);
            }
            return u;
        }
        public static void main(String[] args) {
            //创建Callable实现类的实例
            ImplCallable01 implCallable01 = new ImplCallable01();
            //使用FutureTask类进行包装Callable对象,FutureTask对象封装Callable对象的call()方法的返回值
            FutureTask<Integer> futureTask = new FutureTask<>(implCallable01);
            //开启futureTask线程
            for(int i=0;i<11;i++){
                System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
                //i=10的时候创建future线程
                if (i==10){
                    //使用FutureTask对象作为Thread对象的target创建并启动新线程
                    new Thread(futureTask,"有返回值的线程FutureTask").start();
                }
            }
            //futureTask结束时,获取返回值
            //5.调用FutureTask对象的get()方法获取子线程执行结束后的返回值。
            try {
                System.out.println("子线程返回值:"+futureTask.get());
               // get方法会阻塞,直到子线程执行结束后才返回
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

     





  • 相关阅读:
    KETTLE:mongdb与mysql互传数据
    6.azkban的监控
    5.azkaban权限管理
    3.azkaban3.0测试
    2.azkaban3.0安装
    1.编译azkaban
    十六:The YARN Service Registry
    十四:Using CGroups with YARN
    十二:NodeManager
    十 Writing YARN Applications
  • 原文地址:https://www.cnblogs.com/wdyjt/p/14515337.html
Copyright © 2011-2022 走看看