zoukankan      html  css  js  c++  java
  • java基础知识(11)---多线程

    多线程:
    进程:正在进行中的程序。其实进程一个应用程序运行时的内存分配空间线程:其实就是进程中一个程序执行控制单元,一条执行路径。进程负责的是应用程序的空间的标示。线程负责的是应用程序的执行顺序。
    
    一个进程至少有一个线程在运行,当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序,每个线程在栈区中都有自己的执行空间,自己的方法区、自己的变量。
    jvm在启动的时,首先有一个主线程,负责程序的执行,调用的是main函数。主线程执行的代码都在main方法中。
    当产生垃圾时,收垃圾的动作,是不需要主线程来完成,因为这样,会出现主线程中的代码执行会停止,会去运行垃圾回收器代码,效率较低,所以由单独一个线程来负责垃圾回收。 
    
    随机性的原理:因为cpu的快速切换造成,哪个线程获取到了cpu的执行权,哪个线程就执行。
    
    返回当前线程的名称:Thread.currentThread().getName()
    线程的名称是由:Thread-编号定义的。编号从0开始。
    线程要运行的代码都统一存放在了run方法中。
    
    线程要运行必须要通过类中指定的方法开启。start方法。(启动后,就多了一条执行路径)
    start方法:1)、启动了线程;2)、让jvm调用了run方法。
    
    创建线程的第一种方式:继承Thread ,由子类复写run方法。
    步骤:
    1,定义类继承Thread类;
    2,目的是复写run方法,将要让线程运行的代码都存储到run方法中;
    3,通过创建Thread类的子类对象,创建线程对象;
    4,调用线程的start方法,开启线程,并执行run方法。
    
    线程状态:
    被创建:start()
    运行:具备执行资格,同时具备执行权;
    冻结:sleep(time),wait()—notify()唤醒;线程释放了执行权,同时释放执行资格;
    临时阻塞状态:线程具备cpu的执行资格,没有cpu的执行权;
    消亡:stop()
    
    创建线程的第二种方式:实现一个接口Runnable。
    步骤:
    1,定义类实现Runnable接口。
    2,覆盖接口中的run方法(用于封装线程要运行的代码)。
    3,通过Thread类创建线程对象;
    4,将实现了Runnable接口的子类对象作为实际参数传递给Thread类中的构造函数。
    为什么要传递呢?因为要让线程对象明确要运行的run方法所属的对象。
    5,调用Thread对象的start方法。开启线程,并运行Runnable接口子类中的run方法。
    Ticket t = new Ticket();
    /*
    直接创建Ticket对象,并不是创建线程对象。
    因为创建对象只能通过new Thread类,或者new Thread类的子类才可以。
    所以最终想要创建线程。既然没有了Thread类的子类,就只能用Thread类。
    */
    Thread t1 = new Thread(t); //创建线程。
    /*
    只要将t作为Thread类的构造函数的实际参数传入即可完成线程对象和t之间的关联
    为什么要将t传给Thread类的构造函数呢?其实就是为了明确线程要运行的代码run方法。
    */
    t1.start();
    
    为什么要有Runnable接口的出现?
    1:通过继承Thread类的方式,可以完成多线程的建立。但是这种方式有一个局限性,如果一个类已经有了自己的父类,就不可以继承Thread类,因为java单继承的局限性。
    可是该类中的还有部分代码需要被多个线程同时执行。这时怎么办呢?
    只有对该类进行额外的功能扩展,java就提供了一个接口Runnable。这个接口中定义了run方法,其实run方法的定义就是为了存储多线程要运行的代码。
    所以,通常创建线程都用第二种方式。
    因为实现Runnable接口可以避免单继承的局限性。
    
    2:其实是将不同类中需要被多线程执行的代码进行抽取。将多线程要运行的代码的位置单独定义到接口中。为其他类进行功能扩展提供了前提。
    所以Thread类在描述线程时,内部定义的run方法,也来自于Runnable接口。
    
    实现Runnable接口可以避免单继承的局限性。而且,继承Thread,是可以对Thread类中的方法,进行子类复写的。但是不需要做这个复写动作的话,只为定义线程代码存放位置,实现Runnable接口更方便一些。所以Runnable接口将线程要执行的任务封装成了对象。
    -------------------------------------------------------
    //面试
    new Thread(new Runnable(){  //匿名
    public void run(){
    System.out.println("runnable run");
    }
    }
    {
    public void run(){
    System.out.println("subthread run");
    }
    }.start();  //结果:subthread run
    ---------------------------------------------------------
    Try {
    Thread.sleep(10);
    }catch(InterruptedException e){}// 当刻意让线程稍微停一下,模拟cpu 切换情况。
    
    多线程安全问题的原因:
    通过图解:发现一个线程在执行多条语句时,并运算同一个数据时,在执行过程中,其他线程参与进来,并操作了这个数据。导致到了错误数据的产生。
    
    涉及到两个因素:
    1,多个线程在操作共享数据。
    2,有多条语句对共享数据进行运算。
    原因:这多条语句,在某一个时刻被一个线程执行时,还没有执行完,就被其他线程执行了。
    
    解决安全问题的原理:
    只要将操作共享数据的语句在某一时段让一个线程执行完,在执行过程中,其他线程不能进来执行就可以解决这个问题。
    
    如何进行多句操作共享数据代码的封装呢?
    java中提供了一个解决方式:就是同步代码块。
    格式:
    synchronized(对象) {  // 任意对象都可以。这个对象就是锁。
    需要被同步的代码;
    }
    

      

  • 相关阅读:
    Java实现 LeetCode 792 自定义字符串排序(暴力)
    Java实现 LeetCode 792 自定义字符串排序(暴力)
    asp.net session对象的持久化
    Java实现 LeetCode 791 自定义字符串排序(桶排序)
    Java实现 LeetCode 791 自定义字符串排序(桶排序)
    Java实现 LeetCode 791 自定义字符串排序(桶排序)
    Java实现 LeetCode 790 多米诺和托米诺平铺(递推)
    Java实现 LeetCode 790 多米诺和托米诺平铺(递推)
    Java实现 LeetCode 790 多米诺和托米诺平铺(递推)
    小白也能看懂的约瑟夫环问题
  • 原文地址:https://www.cnblogs.com/ipetergo/p/6617990.html
Copyright © 2011-2022 走看看