Java基础第二十天--多线程1

来源:互联网 发布:ssh连接linux 编辑:程序博客网 时间:2024/06/07 20:02

多线程
进程:正在运行的应用程序,内存空间占用
线程:是应用程序的执行路径,是执行单元
单线程:一个应用程序只有一条执行路径
多线程:一个应用程序的执行路径有多条

每个线程都有一个优先级

 

1. 创建线程的方式
创建新执行线程有两种方式:
1) 方案1
   
a)声明为Thread子类
    b)该子类重写Thread的run()方法
        run()方法就是Java提供的一个入口,让我们去写我们需要被多线程执行的代码
    c)创建自定义类对象,调用start()

   start()方法,它首先的作用,就是启动线程
   其次,才是自动调用run()方法
   如果直接使用run(),那么仅仅是普通方法的调用

<span style="font-size:14px;"> class PrimeRun extends Thread{   public void run(){}  }   PrimeRun p = new PrimeRun();  p.start();</span>


  Thread类有一个私有的字符数组存储线程名  private char name[];
   
  获取线程名称
  public final String getName()
  默认名称:Thread-编号,从0开始
  
  改变线程名称
  public final void setName(String name)
  
  于是我们自然联想到我们自定义类的时候的成员变量的get set方法
  那么是不是构造方法也有体现呢?
  
  public Thread()
  public Thread(String name)
  public Thread(Runnable target)
  public Thread(Runnable target, String name)
  
 2) 方案2
  声明实现Runnable接口的类,该类然后实现run()方法。
  创建该类的实例,并在创建Thread时作为构造参数传递并启动
  (该实例对象作为参数的目的是想让线程对象走实现了Runnable接口的对象的run()方法)
 

 class PrimeRun implements Runnable{   public void run(){}  }  PrimeRun p = new PrimeRun();  new Thread(p).start();    public static Thread currentThread():返回当前正在执行的线程对象  Thread.currentThread.getName()

  
 问题:既然有了第一种方式,为什么还要有第二种方式?
 因为类只能单继承,而接口可以多实现。所以以后要用第二种方式实现,具备可扩展性。
 比如说我现在有一个继承了某个父类的子类想实现多线程,但是父类并没有继承Thread类,
 于是用第一种方法并不合适(需要让它的父类先实现多线程,但是父类可能并没有必要实现)
 所以直接用第二种方法实现接口,可扩展性的体现
 
 一般来说,被多线程操作的代码是比较复杂和耗时的;需要多次执行,被多个人访问的
 多线程程序是没办法进行断点调试的;而单线程总是能够通过断点调试进行Debug的
 
2. 卖票案例
 需求:现在有票100张,有3个窗口
 问题:
 a) 同一张票卖多次
      如果一个操作是最基本的,就不会有任何问题
      但是,如果一个操作包含了两个以上的操作,
      那么,其他的线程可能在中间的那一刻出现,导致卖了同一张票
 b) 出现0票和-1票
      在线程sleep(10)的时候,可能三个进程都进入到run()方法内部在睡眠
      所以会出现0票和-1票的情况

3. 线程的安全问题
 问什么会出问题?
 a) 程序是多线程程序
 b) 多个线程共享数据
 c) 有多条语句对共享数据进行操作 -- 加Synchronized代码块
 
 1)同步代码块
 我们通过一种锁的机制--同步机制
 格式:synchronized(对象锁){//需要被锁的代码(特别是多条语句操作}
 注意
 a) 这里的锁对象在多线程操作中必须一致
 b) 同步代码块这部分相当于是单线程执行,所以应该尽量缩短这部分的内容
 
 问题:同步代码块的锁对象可以是什么?可以是任意对象
 
 2)同步方法(方法锁){}
 private synchronized void sendTicket()
 
 同步方法的锁对象是谁? --this
 静态方法的锁对象是谁? --是当前类的字节码文件对象 Ticket.class
 
 Class getClass  --返回此Object的运行时类对象
 Class 数据类型.class静态属性得到的也是该数据类型对应的字节码文件对象
 
 总结:
 我们使用多线程是为了提高CPU的使用率,使程序运行的更快;
 但是锁的使用,由于要更改及判断锁的状态,所以实际上是降低效率的
 我们之前讲到
 vector是线程安全的,所以效率低  -->  原因就是vector的方法使用Synchronized关键字
 而ArrayList是线程不安全的,但是效率高
 StringBuffer是线程安全的,所以效率低;
 而StringBuilder是线程不安全的,但是效率高
   
 对于JavaEE来讲,多线程技术已经很成熟了,配置配置就可以了
 对于Android来讲,可能需要我们自己来开线程

0 0