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

     线程间的任务不同,但是线程操作的数据相同
      有共享数据
      操作共享数据的代码超过一句

    多线程:

      多线程的程序可以包括多个顺序执行流,多个顺序流之间互不干扰
      实现同时执行的效果,实际上是多个线程在争抢CPU
      可以实现不同功能的同时执行
      多线程不一定能够提高效率,但是可以合理的使用PCU资源
      多线程的运行结果是不同的,因为线程在争抢CPU,这就是多线程的随机性
      进程(Process):
        每个运行中的程序就是一个进程
        正在运行的程序,也就是在内存中开辟的内存空间
    
      线程(Thread):
        负责程序执行的一条执行路径,也称为一个执行单元
        进程的执行实际上是线程在执行
        一个进程至少会有一个线程(Main Thread),主线程执行main函数代码
        当一个进程中有多个线程时,就是多线程程序
        线程是随着任务的存在而存在,随着任务的结束而消失   任务(Task):     每个线程需要执行的代码     任务代码都有其存储位置     主线程的任务代码在main函数,垃圾回收线程的任务代码在finalize函数中
     JVM(Java 虚拟机)是不是多线程?
    
      至少有一个负责正常执行的线程,也就是执行main函数中的代码----主线程
       还有一个负责垃圾回收的线程,也就是执行finalize函数中的代码----垃圾回收线程
    
      JVM在后台提供了一个超级线程来执行垃圾回收
      每个对象都可以被回收,回收的功能定义在Object的finalize()方法中
      运行垃圾回收器,调用System的gc()方法

    创建线程:

    创建线程的第一种方式:
      
    1 创建一个类继承Thread   2 重写Thread类中的run方法     创建线程是为了执行任务     任务代码必须有存储位置,run方法就是任务代码的存储位置   3 创建子类对象,实际在创建线程   4 启动线程     主线程的任务代码在main函数中     子线程的任务代码在run函数中 

    run()方法只是一个普通的方法调用,不具备启动线程的功能
    start()方法会启动线程并执行run()中的代码

    创建线程的第二种方式:

      为了解决临界资源的问题,需要使用创建线程的第二种方式
      1 创建实现了Runnable接口的子类
      2 重写Runnable接口的run方法
      3 创建实现了Runnable接口的子类的对象
      4 创建Thread类的对象,也就是创建线程
      5 把实现了Runnable接口的子类对象作为参数传递给Thread的构造方法

    优点:
      把线程任务进行了描述,也就是面向对象
      实现了线程任务和线程对象的分离,线程执行什么任务不再重要,只要实现了Runnable接口的子类对象都可以作为参数传递给Thread的构造方法
      实现了接口的同时还可以继承父类

    创建线程的第三种方式:

    
    

      1 创建Callable接口的实现类

      2 重写Callable接口的call方法

      3 使用FutureTask类来包装Callable对象,该FutureTask对象封装了该call方法的返回值

      4 将FutureTask对象作为参数传递给Thread的构造方法

      5 使用FutureTask对象的get方法获得子线程结束后的返回值


    总结: 

      通过继承Thread类和或者实现Runnable接口,Callable接口都可以实现多线程

      通过接口实现的两种方式相似,只是Callable接口定义的方法有返回值

     使用继承类和接口创建多线程的方式对比:

      Runnable和Callable线程类只是实现了Runnable和Callable接口,还可以继承其他类

      多个线程可以共享同一个对象,可以处理同一份资源

      访问当前线程必须使用Thread.currentThread方法

      Thread线程类已经继承了Thread,不能再次继承其他类

      访问当前线程只需this

    
    
    为什么不能直接创建Thread类,然后调用start方法?
    
      任务代码必须写在run方法中,而Thread类中的run方法没有实现任何功能,代码执行没有结果
       所以只有继承Thread类,重写run方法

    多线程内存:

      在栈中为主线程开辟内存
      多线程不遵循先进后出,每个线程在栈中都有内存,谁先获得CPU,就先执行
      当线程执行完自己的任务代码,线程就从栈中消失
      只有所有线程都结束,整个进程才结束

    synchronized:

    synchronized代码块的锁:obj
    synchronized同步函数的锁:this
    静态同步函数:
      静态函数进内存的时候不存在对象,但是存在其所属类的字节码文件,属于Class类型的对象,所以静态同步函数的锁是其所属类的字节码文件对象
    
    避免死锁:
      容易发生在锁的嵌套

    线程间的通信:   

    线程间的任务不同,但是线程操作的数据相同
    有共享数据
    操作共享数据的代码超过一句

    等待唤醒机制:      

    必须用在同步中,因为同步中才有锁
    指明让持有锁的线程去等待或被唤醒
    等待的线程会放弃锁  
    wait(),notify(),notifyAall()为什么定义在Object中?
       
       wait(),notify(),notifyAall()必须用在同步中,因为同步中才有锁
       锁是任意对象,任意对象都可以调用的方法需要定义在Obbject中 

    jdk1.5 多线程的实现方式:

      jdk1.5之前:
        对锁的操作是隐式的
        synchronized(obj)//获取锁
        {
    
        }//释放锁
      jdk1.5之后:
        import.util.concurrent.Locks;
        有一个描述锁的Lock接口,锁被面向对象
        使用Lock的子类ReentrantLock创建一把锁

    使用Lock替代同步代码块的方式:

    使用Lock替代同步代码块的方式:
      1 创建一把锁
      2 把之前写在同步代码块中的代码写在lock()和unlock()之间
        lock()获取锁
        unlock()释放锁
        await()等待
          单独的定义在Condition接口中
          也被面向对象 
        signal()唤醒一个等待线程
        signalAll()唤醒所有等待线程
      3 得到一个和锁绑定的Condition对象
    
    jdk1.5对唤醒等待方法也进行了单独的描述,描述的接口是Condition
    唤醒等待方法必须结合着锁来使用,所以使用Lock的newCondition()方法来获得和锁绑定的对象

    用Lock替代同步代码块之后出现了IllegaMonitorStateException(无效的监视器异常)?

     因为wait(),notify(),notifyAll()必须用在同步代码块中,而同步代码块被Lock替代掉了
     

    守护线程:

    垃圾回收线程就是一个守护线程
    可以看成后台线程,依赖于前台线程
    当前台线程全部结束时,即使守护线程的任务代码没有执行完也会立刻结束
    在线程启动前设置启动线程
    
      setDaemon()设置为守护线程
    
      join()加入运行,主线程会让着此线程,等到此线程运行完主线程才会继续执行

    线程池:

    java.util.concurrent
      可以创建线程的对象
    接口:ExeutorService
    
    创建线程池:
    
      execute()开始执行任务
    
      创建只有一个线程的线程池
        任务只能一个一个执行,按照任务提交的先后顺序执行
        newSingleThreadExecutor()    
      创建固定个数的线程池
        任务数量和线程数量相同时,任务会同时执行
        任务数量大于线程数量时,多出来的任务会等待线程池中已有的线程空闲下来去执行
        newFixedThreadPool()
      创建缓冲的线程池
        自身会创建一定数量的线程
        线程数量大于任务数量,会自动销毁空闲的线程
        当任务增加时又会自动增加线程
        newCachedThreadPool()
      创建数量无限的线程池
        空闲的线程不会被销毁
        newScheduledThreadPool()

    使用匿名内部类创建线程:

      new Thread()
      {
        public void run()
         {
      
         }
      }.start();
    
     
    
      new Thread(new Runnable()
      {
        public void run()
        {
    
        }
      }).start();
    
     
    
    
      Runnable r = new Runnable()
      {
        public void run()
        {
    
        }
    
      };
      new Thread(r).start();
  • 相关阅读:
    中小企业需要企业邮箱吗?中小性公司选什么邮箱性价比高?
    主流电子邮箱有哪些?你的邮箱选对了吗?
    外贸邮箱选择什么企业邮箱更安全?
    企业邮箱适用于哪些行业?公司邮箱都用什么?
    如何注册公司收费邮箱?注册公司邮箱有哪些优势?
    convert_cyr_string — 将字符由一种 Cyrillic 字符转换成另一种
    chunk_split — 将字符串分割成小块
    addslashes — 使用反斜线引用字符串
    addcslashes — 以 C 语言风格使用反斜线转义字符串中的字符
    extract — 从数组中将变量导入到当前的符号表
  • 原文地址:https://www.cnblogs.com/roxy/p/7290497.html
Copyright © 2011-2022 走看看