黑马程序员_多线程

来源:互联网 发布:义乌ps美工培训 编辑:程序博客网 时间:2024/06/10 20:03

---------------------- android培训java培训、期待与您交流! ----------------------

多线程
C++的多进程是OS系统并发的一个任务
Java中没有多进程,一个JVM就是一个进程

线程是在进程中并发的一个顺序的执行流程

多进程:划分时间片,宏观上并行,微观上串行
多线程:cpu在进程内部再划分时间片

CPU ,代码 ,数据
进程:进程间数据独立
线程:数据空间共享,堆空间的共享(堆空间中存放的是对象),栈空间是独立的
所以线程间切换容易,称为轻量级进程

一个线程对象代表了一个线程,并非就是一个线程
线程是操作系统中负责维护的资源
java.lang.Thread类的一个对象就代表一个线程
线程是底层OS维护的资源,JVM跑在OS上,在JVM中创建一个Thread对象,调用其start()方法,底层OS会申请一个线程资源,线程

对象可到底层管理一个线程
创建好线程之后,把要让线程执行的代码封装到线程对象中(覆盖run()方法)

实现线程代码的方式:
1、继承Thread 类,覆盖run()方法
   去底层申请线程并运行,对线程对象调start()方法,main方法是一个主线程
   宏观并行,微观串行
2、实现Runnable接口
  使用多态获得Runnable对象,成为目标对象
  再利用目标对象构造线程对象  Thread t = new Thread(target);


多线程的状态转换图

  ■ 阻塞状态
 
    ▲ 初始状态                 ▲阻塞状态                   ▲终止状态
        \                               /               ^ 1                        ^
         \                           /                     \ 2sleep          /
           \start                /                           \ 3join        /stop
             \                  /                                 \           /
                V         V                                        \     /
         ▲ 可运行状态 _ _ _  OS选中 _  _ _\ ▲运行状态
          (只缺CPU)   \  CPU到期或调用yield
          
    下面为线程中的7中非常重要的状态:(有的书上也只有认为前五种状态:而将“锁池”和“等待池”都看成是“阻塞”状态的

特殊情况:这种认识也是正确的,但是将“锁池”和“等待池”单独分离出来有利于对程序的理解)
    1,初始状态,线程创建,线程对象调用start()方法。
    2,可运行状态,也就是等待Cpu资源,等待运行的状态。
    3,运行状态,获得了cpu资源,正在运行状态。
    4,阻塞状态,也就是让出cpu资源,进入一种等待状态,而且不是可运行状态,有三种情况会进入阻塞状态。
      1)如等待数据输入(输入设备进行处理,而CPU不处理),则放入阻塞,直到输入完毕,阻塞结束后会进入可运行状态。
      2)线程休眠,线程对象调用sleep()方法,阻塞结束后会进入可运行状态。
        public static void sleep(long millis)
                  throws InterruptedException
       括号中以毫秒为单位, 使线程停止一段时间,间隔期满后,线程不一定立即恢复执行。
       当main()运行完毕,即使在结束时时间片还没有用完,CPU也放弃此时间片,继续运行其他程序。
      try{
       Thread.sleep(1000);
      }catch(InterruptedException e){
       e.printStackTrace(e);
      }
      线程中有异常,只能trycatch,子类中不能抛出比父类更多的异常,父类run方法没有抛出异

常。
      3)线程对象2调用线程对象1的join()方法,那么线程对象2进入阻塞状态,直到线程对象1中止。
         public final void join() throws InterruptedException
       表示其他运行线程放弃执行权,进入阻塞状态,直到调用线程结束。
       实际上是把并发的线程变为串行运行。
     t1 num
     t2 char  if(c=='m') -> t1.join()
     //t2对t1调用join,t2进入了阻塞状态
     //当条件成立时,t1加入打印数字,一直到打印完,此时t2继续运行

    5,中止状态,也就是执行结束。
    6,锁池状态
    7,等待队列
 
共享数据的并发处理

  ■ 数据的错误发生
  多线程并发访问同一个对象(临界资源)
  破坏了原子操作,就会发生数据不一致的情况

  ■ 多线程同时并发访问的资源叫做临界资源。
    多个线程同时访问对象并要求操作相同资源时分割了原子操作就会出现问题。(原子操作,不可再分的操作)会出现数据的不

一致或数据不完整,为避免这种现象采用对访问的线程做限制的方法。

  ■ 互斥锁机制,利用每个对象都有一个monitor(锁标记),当线程拥有这个锁标记时才能访问这个资源,没有锁标记便进入锁池

。任何一个对象系统都会为其创建一个互斥锁,这个琐是为了分配给线程的,防止打断原子操作。每个对象的锁只能分配给一个线

程。

  ■ Synchronized用法
    1.Synchronized修饰代码块(同步代码块),
      public void push(char c){
          synchronized(this)//只有持有当前对象锁标记的线程才能访问这个代码块
         {
           ...
          }
      }

      对括号内的对象加锁,只有拿到锁标记的对象才能执行该代码块
    2.Synchronized修饰方法
        public synchronized void push(char c) {
             ...
        }
       在整个方法里,对当前对象的加锁,只有拿到锁标记的对象才能执行该方法。

  ■
    ▲ 初始状态                ▲阻塞状态                ▲终止状态
                   \                     /          ┍ 1                     ┓
                    \                  /              \ 2sleep            /
                      \start       /                    \ 3join         /stop
                       \           /                          \           /
                         ┙     ┕                                \     /
         ▲ 可运行状态  _ _ _ OS选中 _ _ _\ ▲运行状态
          (只缺CPU)    \  CPU到期或调用yield
                       ┍                                    /
                            \                             /
                             \        Synchronized/
                               \                    /
                                 \               ┕
                               ▲ 锁池状态
         

    锁池:一个空间,每个对象都有一个,用来存放等待锁标记的线程
    当一个对象中有了锁标记,不会释放其它对象的锁标记。

    当t1线程正在访问对象O的同步方法时,别的线程t2不能访问O的任何同步方法,但还是可以访问其它的非同步方法

       
  ■ 构造方法   ×对象没有完全构造好了,没有当前对象概念
    抽象方法   ×抽象方法没有代码块,没用
    静态方法   √是对类对象的加锁
         
    ☆注意:构造方法不能Synchronized修饰
    静态方法可以用Synchronized修饰(是对类对象加锁,类对象会在反射时讲到)
    抽象方法不能用Synchronized修饰,不影响子类覆盖,子类在覆盖这个方法是可以加Synchronized,也可以不加Synchronized

,所以根据Java不允许写废代码的特点是不能写在一起。

----------------------- android培训java培训、java学习型技术博客、期待与您交流! ----------------------

原创粉丝点击