黑马程序员——多线程-整理笔记

来源:互联网 发布:加强网络管理 防范 编辑:程序博客网 时间:2024/05/22 00:32

                                                  ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------


多线程的概念

          首先介绍什么是进程:进程是正在执行的程序,每个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元

          线程是其实就是进程中一个独立的控制单元,线程在控制着执行,一个进程至少有一个线程。

线程和进程的不同:

        ①地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;;
        ②资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源;
        ③线程是处理器调度的基本单位,但进程不是;

线程和进程的优缺点:

       线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。

多线程的好处:

      在多线程程序中,多个线程被并发的执行以提高程序的效率,CPU不会因为某个线程需要等待资源而进入空闲状态。多个线程共享堆内存(,因此创建多个线程去执行一些任务会比创建多个进程更好。

多线程的特点:

       随机性,谁先抢到谁先执行,执行时间有CPU决定。

线程创建的两种方法:

     方法一:继承Thread类

           步骤:

                 ①定义类继承Thread类;
                 ②复写Thread类中的run方法,将要让线程运行的代码都存储到run方法中;
                 ③通过创建Thread类的子类对象,创建线程对象;
                 ④调用线程的start方法,开启线程,并执行run方法  ;

    继承Thread类的代码示例:

public class Demo extends Thread {public void run() {for (int i = 0; i < 60; i++)System.out.println("Demo run" + i);}}class ThreadDemo {public static void main(String[] args) {Demo d = new Demo();// 创建一个线程d.start(); // start启动线程for (int i = 0; i < 60; i++)System.out.println("main   " + i);}}

        方法二:实现Runnable接口

              步骤:

                ①定义类实现Runnable接口 
                ②覆盖Runnable接口中的run方法。将线程要运行的代码存放在该run方法中;
                ③通过Thread类建立线程对象;
                ④将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数;
                ⑤调用Thread类的start方法开启线程;

       实现Runnable接口的代码示例

public class MyThread {<span style="white-space:pre"></span>public static void main(String[] args) {<span style="white-space:pre"></span>Ticket t = new Ticket();<span style="white-space:pre"></span>// 线程开始<span style="white-space:pre"></span>new Thread(t).start();<span style="white-space:pre"></span>new Thread(t).start();<span style="white-space:pre"></span>}}// 实现Runnable接口class Ticket implements Runnable {<span style="white-space:pre"></span>private int t = 100;<span style="white-space:pre"></span>// 覆run方法<span style="white-space:pre"></span>public void run() {<span style="white-space:pre"></span>while (true) {<span style="white-space:pre"></span>if (t > 0) {<span style="white-space:pre"></span>System.out.println(Thread.currentThread().getName() + ":::"<span style="white-space:pre"></span>+ t--);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}}


实现接口方式和继承类方式的区别?

  实现Runnable接口可以避免单继承的局限性,最常使用实现方式。

  区别:继承Thread:线程代码存放Thread子类run方法中。实现Runnable:线程代码存在接口的子类run方法中。


线程一共分为5种状态:
        ①被创建new 
        ②sleep 睡眠状态,(time)给他一个参数,时间一到就会恢复到临时状态;
        ③wait(等待), 直到被 notify(通知)才会回到临时状态;
        ④stop(消亡状态)  run方法结束了线程也会消亡;
        ⑤临时状态或者被叫(阻塞状态),它具备运行资格,但是没有执行权)。线程被start之后 在等待CPU的执行权;


线程状态图



线程安全:

     线程安全产生的原因:多个线程共同操作同一个共享数据;有多条语句对共享数据进行计算,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。

     解决方案:同步代码块或同步函数。

       同步代码块的格式

           synchronized(对象) {  //任意对象都可以。这个对象就是锁。
                                  需要被同步的代码;
                               }

      同步函数: 所谓的同步函数就是在函数的返回值前面加一个synchronized关键字就是同步函数了。

         同步代码块的锁是参数对象,

         同步函数的锁是this,

         静态同步函数的锁是该类的字节码文件对象。

         在一个类中只有一个同步,可以使用同步函数。如果有多同步,必须使用同步代码块,来确定不同的锁。所以同步代码块相对灵活一些。

    同步线程的前提:

          ①必须要有两个或者两个以上的线程。
          ②必须是多个线程使用同一个锁。
          ③必须保证同步中只有一个线程在运行。
            好处:解决了多线程的安全问题。
            弊端:多个线程需要判断锁,较为消耗资源。

单例设计模式的懒汉式:

           对象是方法被调用时才初始化,也叫对象的延时加载 。下例中Single类进入内存,对象还没有存在,只有调用了getInstance方法时,才建立对象的懒汉式;

           懒汉式的特点就是延迟加载, 不过还是存在问题,如果多线程时会出现安全问题,可以加同步代码块解决问题,加同步时用的锁必须是该类所属的字节码文件对象。

  懒汉式代码示例:

/*  * 延迟加载模式——懒汉式  * 加入同步机制,解决安全问题。但是却带来了效率降低。  * 为了效率问题,通过双重判断的形式解决。  */  class Single{      private static Single s = null;      private Single(){}      public static Single getInstance(){ //锁是谁?字节码文件对象;          if(s == null){              synchronized(Single.class){                  if(s == null)                      s = new Single();              }          }          return s;      }  }
死锁:

   由于线程同步代码中可能嵌套同步,最容易导致的问题就是死锁。程序就停在那里不动了。要尽量避免死锁。

死锁代码示例:

class Test implements Runnable  {      private boolean flag;      Test (boolean flag)      {          this.flag=flag;      }        public void run ()      {          if (flag)          {              synchronized(MyLock.locka)//a锁              {                  System.out.println("if locka");                  synchronized(MyLock.lockb)//b锁                  {                      System.out.println("if lockb");                  }              }          }          else           {              synchronized(MyLock.lockb)//b锁              {                  System.out.println("else lockb");                  synchronized(MyLock.locka)//a锁                  {                      System.out.println("else locka");                  }              }          }      }  }  //定义两种锁的类class MyLock  {      static Object locka = new Object();      static Object lockb = new Object();  }    class  DeadLockDemo  {      public static void main(String[] args)       {          Thread t1 = new Thread(new Test(true));          Thread t2 = new Thread(new Test(false));            t1.start();          t2.start();      }  }  


                                                  ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

0 0
原创粉丝点击