zoukankan      html  css  js  c++  java
  • java-多线程

    多线程

    概述
    • 在一个线程中有多条执行路径

    • 进程:正在执行的程序,他代表着应用程序的执行区域

    • 线程:进程执行路径,就是进程中一个负责程序执行的控制单元。

      ​ 线程总是属于某个进程,进程中的多个线程共享进程的内存

    关于多线程的问题
    • jvm启动时多线程还是单线程的,为什么?

      多线程的,他至少启动了两个线程(主线程和垃圾回收线程)垃圾回收机制这个线程不可能是在程序执行完毕后才启动的,否则的话,我们的程序很容易出现内存溢出

    • 调用start方法和run方法区别?

      调用start方法后,线程进入就绪状态,此时线程对象仅有执行资格,还没有执行权。当该线程对象抢到了执行权的时,方可调用run方法,当run方法执行完毕后,线程死亡,不能复生。

    • 线程的随机性的导致原因?

      在同一时刻,CPU只能执行一个程序,这个多线程的程序其实是CPU的高速切换造成的。

    • 什么时候使用多线程?以及创建线程的目的?

      多线程的引入是为了解决现实生活中的需求的,提高解决问题的效率。

      当许多对象要对同一有限资源进行操作的时候,我们就要使用多线程

    • 线程状态的内容和每一个状态的特点?

      创建线程对象后,并对这个对象进行了一些初始化工作,当调用了start方法后,这个状态局有了执行资格,但是此时还未获得执行权,进入到了就绪状态。当抢到执行权后进入了运行状态,此时该线程既有了执行资格,又有了执行权。当调用run方法后,此线程进入了死亡状态。当然你也可以调用Stop方法令其强制死亡。在运行状态的时候,如果该线程调用了sleep或者wait等方法后,他会进入到阻塞状态,此时这个对象释放了执行资格和执行权,当它的sleep或者wait等方法后,亦或者调用了notify方法,该线程被唤醒,又进入了就绪状态,如此周而复始。

    创建线程的方式
    • 继承Thread类

      • 定义一个类继承Thread类
      • 重写Thread类中的run()方法,run()方法里边是多线程要运行的代码;
      • 创建定义的那个类的对象
      • 调用start()方法开启线程,执行run()方法里的内容。
      package com.xtslife.thread;
      
      /**
       * @author 小涛
       * @create 2019-05-28  18:55
       */
      public class FirstThread extends Thread{
          @Override
          public void run() {
              for (int i= 0;i<=10;i++){
                  System.out.println("线程"+getName()+"正在运行:"+i);
              }
          }
      
          public static void main(String[] args) {
              FirstThread t1 = new FirstThread();
              FirstThread t2 = new FirstThread();
              t1.start();
              t2.start();
          }
      }
      

      线程的声明周期:创建-----阻塞-----运行----死亡

    • 实现Runnable接口

      • 定义一个类实现Runnable接口
      • 重写Runable接口中的run()方法,run()方法里是多线程要运行的代码
      • 创建定义的那个类的对象,并将其作为参数放置于Thread类的对象里。线程的任务都封装在Runnable接口子类对象的run方法中,所以要在线程对象创建时就必须明确要运行的任务。
      • 调用start()方法启动线程,执行run()方法里的内容
      • 总结:两种方法的比较:实现Runnable接口,将线程的任务从线程的子类中分离出来,进行了单独的封装,按照面向对象的思想将任务的封装成了对象,避免了java中单继承的局限性。
      多线程的安全问题
      • 产生的原因
        • 线程访问的延迟
        • 线程的随机性
      • 线程安全问题表现?原因?解决思想?解决具体的体现
        • 当以个线程对象在执行run方法是的某一操作,其他线程进来了,并发的访问了临界资源,破坏了原子操作,造成了数据的不一致
        • 多线程访问的延迟和线程的随机性产生了线程的安全问题
        • 当某一线程对象进入run方法后,如果能做一个标记,说我已经在理面了,其他哥们(线程对象)你就等着吧,等我操作完了,出来了去掉标记你再进去吧,这样一来。原子操作就不会遭到破坏。
        • 具体体现就是给那个原子操作枷锁,是整个操作同步,不让其他线程对象破坏,保证数据的一致性。
      同步解决线程安全问题
      • 同步代码块

        • 同步代码块中的锁可以是任意对象,但是要在成员范围内定义
        • 在局部的话,会导致锁发生变化,因为你每次执行方法,都会重新创建一个对象
        • 同步的前提
          • 至少要有两个线程
          • 同一个锁
        • 同步的好处:提高了安全性
        • 同步的弊端:效率较低
      • 同步函数

        • 同步函数的使用

          • 用synchronized关键字修饰方法即可

            public synchronized void show(){
                //需要的同步代码块
            }
            
        • 同步函数使用的锁

          • 同步函数使用时this对象锁,静态同步函数的锁是(类名.class)
          public class Singleton{
              private Singleton(){}
              private static Singleton s = null;
              public static Singleton getInstance(){
                  if(s==null){
                      synchronized(Singleton.class){
                          if(s==null){
                              s= new Singleton();
                          }
                      }
                  }
               return s ;
              }
          }
          
      死锁

      每个线程都不会释放自己拥有的锁标记,却阻塞在另外的线程所拥有的锁标记的对象池中,就会造成死锁现象。

      产生原因

      假如有A何B两个锁,在A锁中要使用B锁,在B锁中要使用A锁,而他们都不想让,最终导致了死锁。

      • 因为资源不足
      • 进程运行推进的顺序不合适
      • 资源分配不当
      产生死锁的四个条件
      • 互斥条件:一个资源每次只能被一个进程使用

      • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

      • 不剥夺条件:进程已获得的资源,在未使用之前,不能强行剥夺。

      • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

        只要上述条件之一不满足,就不会发生死锁。

      如何解决?
      • 不同时在A锁中使用B锁,B锁中使用A锁
      线程状态
      • CPU

        • CPU的执行资格:可以被CPU的处理,在处理队列中排队
        • CPU的执行权:正在被CPU的处理
      • 创建:使用start()开启线程

      • 运行:具备着执行资格,具备着执行权。

      • 冻结:释放执行权,同时释放执行资格

        从运行到冻结的方式

        • sleep(time),sleep(time)时间到,进入临时阻塞状态(具备着执行资格,但是不具备执行权,正在等待执行权)
        • wait()线程等待,notify()线程唤醒,进入临时阻塞状态
      • 消亡

        从运行到消亡的方式

        • stop()终止线程
        • run()方法结束,线程任务结束
      几个方法的使用
      • 为什么wait(),notify(),notifyAll()都定义在Object类中?

        • 这些方法存在于同步中
        • 使用这些方法时必须要标识所属的同步锁
        • 锁可以是任意对象,所以任意兑现调用的方法一定定义Object类中
      • wait()和sleep()的区别?

        • 对时间指定货而言
          • wait():可以不指定时间
          • sleep():必须指定时间
        • 对执行权和锁而言
          • wait():释放了CPU的执行权(资格也没了),释放锁,存储于线程池。
          • sleep():释放CPU执行权,不释放锁(会自动醒)
      • 停止线程

        • 通过控制循环
        • interrupt()方法
          • stop已过时,被interrupt取代
      • 守护线程,后台线程

        你只要把一个线程设置为守护线程,那么主方法线程结束,不管什么情况,守护线程就结束。

      • join:加入线程,把执行权抢夺,自己执行完毕,其他线程才可能有机会执行

      • toString():线程名称,优先级,线程组(是有多个线程组成的,默认的线程组是main)

      • yield():让本线程暂停执行,把执行权给其他线程

      • setProproty(int num):设置线程的优先级

      • getPrinrity()获取线程的优先级

        • 线程级别1-10
        • 默认级别5
      LOCK&Condition接口
      Scanner类

      接收从键盘输入的数据

      • 这是java中提供的类。在util包中
      • 基本用法:
        • Scanner sc = new Scanner(System.in);
        • int a =sc.nextInt();


    作者:关小涛
    学习和分享是博客最大的乐趣,欢迎大家取之所需。
    努力是自己努力的原因,每周天写博客总结工作中的新技能和出现的问题
  • 相关阅读:
    kvm介绍
    正式班D24
    正式班D23
    正式班D21
    正式班D20
    正式班D19
    正式班D18
    正式班D17
    正式班D16
    正式班D15
  • 原文地址:https://www.cnblogs.com/XtsLife/p/11015275.html
Copyright © 2011-2022 走看看