A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© g207776411 中级黑马   /  2018-4-23 15:40  /  340 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 小石姐姐 于 2018-4-26 14:16 编辑

Java多线程笔记


Day_11多线程
多线程是怎么实现的,线程是什么:
  
      进程:当前正在运行的程序,一个应用程序在内存中的执行区域
      线程:线程依赖于进程,他是进程中的执行控制单元,执行路
进程就是一个应用程序
  • 一个进程可以有一个线程,也可以有多个线程 ** 单线程:安全性高,效率低* 多线程:安全性低,效率高                 例如:迅雷\360安全卫士


    • 单线程和多线程的特点


      • 单线程:同一时间只能做一件事情,安全性高,效率低,
      • 多线程:同一时间可以做多件事情,安全性低,但是效率高;


        • 多线程可以实现并发:并行发生,同时发生,多线程就可以实现并发




  • 多个线程执行程序的时候会提高效率
  • 线程:


    • Thread,是一个进程中的一个执行路径
    • 举例


      • 一个进程可以有多个或多个线程,每个线程可以执行自己的代码
      • 多个线程各自执行的任务可以同时进行
      • 线程的执行依靠CPU调用分配


        • 单核CPU:靠CPU不断高速的随机的切换执行的线程,达到看似同时进行的效果
        • 多核CPU:每个CPU可能完全执行一个线程,或者多个CPU各自不断告诉随机切换,更高效





同步:指的是单线程,一步一步的执行,一个执行完再执行下一个
异步:指的是多线程,同时进行
阻塞:指的是上一步成还没有执行完,程序就停留在这里
CPU在执行程序的随机性,所以多个线程同时运行,不一定哪一个线程在前
多线程两种实现的方式:                                                线程安全问题:                        多线程卖火车票练习:
​        假如一个线程执行static void sleep( )方法,就是让线程先睡一会,
​        假如不使用synchronized来给多线程上锁,则就会发生负数票数,异常
  
          /*
   * 12306卖火车票
   *
   */
  public class MyThreadTest {
      public static void main(String[] args) {
          // 创建Ticket
          // Ticket tick = new Ticket();
          Ticket2 tick = new Ticket2();
          // 创建多线程对象
          Thread t1 = new Thread(tick);
          Thread t2 = new Thread(tick);
          Thread t3 = new Thread(tick);
  ​
          // 修改线程名称
          t1.setName("一号窗口");
          t2.setName("二号窗口");
          t3.setName("三号窗口");
          // 打开线程
          t1.start();
          t2.start();
          t3.start();
  ​
      }
  }
  ​
  ​
  class Ticket implements Runnable {
      // 定义共享资源
      private Integer number = 100;
  ​
      @Override
      public synchronized void run() {
          while (true) {
              // 当票数大于零就继续卖票
              if (number > 0) {
                  try {
                      Thread.sleep(60);
                  } catch (InterruptedException e) {
                      // TODO Auto-generated catch block
                      // e.printStackTrace();
                      System.out.println("----------");
                  }
                  System.out.println(Thread.currentThread().getName() + "火车票剩余量:" + number);
                  number--;
              } else {
                  return;
              }
          }
      }
  ​
  }
  ​
  //
  class Ticket2 implements Runnable {
      // 定义共享资源
      private Integer number = 100;
  ​
      @Override
      public  void run() {
          while (true) {
              
              // 当票数大于零就继续卖票
              method();
              
          }
      }
  ​
  ​
  //这里我们抽取方法的时候
      private  synchronized void method() {
          if (number > 0) {
              try {
                  Thread.sleep(60);
              } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                  // e.printStackTrace();
                  System.out.println("----------");
              }
              System.out.println(Thread.currentThread().getName() + "卖掉了第" + number+"张票");
              number--;
          } else {
  //              System.out.println("票卖完了");
              return;
          }
      }
  ​
  }同步代码块
即使用关键字synchronized修饰的方法,一旦被一个线程访问,则整个方法全部锁住,其他线程则无法访问
  • synchonized


    • 注意:


      • 静态方法的锁对象是当前类的字节码
      • 非静态方法的锁对象是this




在run方法中抽取的方法,并且被synchronized修饰,或者方法体内被        synchronized(锁){                         需要加锁的代码块               }
  
  ​
  private synchronized void printMehtod(int count, HashSet<Integer> array) {
              // 金额总和
              int sum = 0;
              System.out.print("在此次抽奖过程中," + Thread.currentThread().getName() + "总共产生了" + count + "个奖项,分别为:");
              for (Integer integer : array) {
                  sum += integer;
                  System.out.print(integer + ",");
              }
              System.out.println("最高奖项为" + Collections.max(array) + "元,总计额为" + sum + "元");
              //产生出最大奖项
              for (Integer integer : array) {
                  if (integer==800) {
                      System.out.println(Thread.currentThread().getName()+"产生最大奖,最大奖为:"+integer);
                  }
              }
          }
Synchronized的应用场景
​        在使用线程时,我们先要控制CPU的随机分配.,那我们将Run方法中的操作进行上锁,当一个线程执行完毕以后,后一个线程才会执行
​        这里我们要分清楚,线程共同的元素和非共有的元素
创建线程有两种方式
​        第一种方式:
  • 创建一个类  Java.lang.Thread类:实现了Runnable接口


    • 构造方法


      • Thread Thread(): 创建Thead对象
      • Thread Thread(Runnable r): 通过Runnable对象创建Thread对象
      • Thread Thread(Runnable r, String threadName): 通过Runnable对象创建Thread对象并指定线程名


    • 成员方法


      • void run(): 用于让子类重写, 表示该线程要执行的任务. 不能直接调用
      • void start(): 启动线程, 即让线程开始执行run()方法中的代码
      • String getName(): 获取线程的名称
      • void setName(String name): 设置线程名称


    • 静态方法


      • static Thread currentThread(): 返回对当前正在执行的线程对象的引用
      • static void sleep(long millis): 让所在线程睡眠指定的毫秒




        第二种方式:     自己创建一个实现Runnable接口的类
                        *         格式:                                
                                                类名     对象名=  new 类名();
                                        使用线程就创建几个Thread对象
                                                Thread  t1=new Thread(对象名)
                                                Thread  t1=new Thread(对象名)
Runnable接口出现的原因
  • 因为Java只支持单继承, 如果继承了Thread类, 就无法继承其他类, 局限性太大, 所以使用实现Runnable接口的方式, 既能继承其他类, 还能实现多个接口, 不会影响类的扩展性


多线程实现方式2:
  • 实现Runnable接口, 重写run()方法
  • 步骤


    • 定义一个类, 实现Runnable接口
    • 在子类中重写父类的run()方法
    • 创建一个子类的对象
    • 创建Thread对象, 在其构造方法中传入刚才创建的子类的对象
    • 调用Thread对象的start()方法启动一个线程





0 个回复

您需要登录后才可以回帖 登录 | 加入黑马