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();


    作者:关小涛
    学习和分享是博客最大的乐趣,欢迎大家取之所需。
    努力是自己努力的原因,每周天写博客总结工作中的新技能和出现的问题
  • 相关阅读:
    /etc/sysctl.conf 控制内核相关配置文件
    python 并发编程 非阻塞IO模型
    python 并发编程 多路复用IO模型
    python 并发编程 异步IO模型
    python 并发编程 阻塞IO模型
    python 并发编程 基于gevent模块 协程池 实现并发的套接字通信
    python 并发编程 基于gevent模块实现并发的套接字通信
    python 并发编程 io模型 目录
    python 并发编程 socket 服务端 客户端 阻塞io行为
    python 并发编程 IO模型介绍
  • 原文地址:https://www.cnblogs.com/XtsLife/p/11015275.html
Copyright © 2011-2022 走看看