黑马程序员——关于多线程

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流!----------------------

 

何为线程?首先我们要先知道何为进程,所谓进程,就是一个正在执行的程序。打开任务管理器我们就可以看到这些进程。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。线程就是进程中的一个独立的控制单元,它控制着进程的执行。一个进程中至少有一个线程。比如,java虚拟机启动的时候会有一个进程java.exe,该进程中至少有一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之为主线程。其实在java虚拟机启动时不止这一个线程,还有负责垃圾回收机制的线程。

所谓的多线程,其实就是多个线程都在获取cpu的执行权,cpu在各个线程之间做着快速的切换,随机执行某一个线程,而因为cpu执行的速度很快,所以各线程看起来好像是同时执行的。

那么,如何创建一个线程呢?有两种方法:

第一种是定义类直接继承Thread类,然后复写Thread类中的run方法(将自定义代码存储在run方法中,让线程运行),最后调用线程的start方法(启动线程,调用run方法)。如果这里不调用start方法,而是调用run方法,那么线程其实是没有启动的,程序只有主线程在运行(忽略垃圾回收机制),主线程单纯地执行了run方法,跟一般类没有区别。

第二种方法有以下几个步骤:

Ø 定义类实现Runnable接口;

Ø 覆盖Runnable接口中的run方法;

Ø 通过Thread类建立线程对象;

Ø将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数;

【这里将Runnable接口的子类对象传递给Thread的构造函数是因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去执行指定对象的run方法,就必须明确该run方法所属对象。】

Ø调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。

比如:

class Ticket implements Runnable{

  private int tick = 100;

  public void run(){

      while(true){

        if(tick>0)

           System.out.println(Thread.currentThread().getName()+"....sale:"+tick--);

               //Thread.currentThread():获取当前调用线程,getName():获取线程的名称。

     }

  }

 }

class TicketDemo{

    publicstatic void main(String[] args) {

     Ticket t = new Ticket();//建立Runnable子类对象

      //将Runnable子类对象作为参数传入Thread构造函数中

     Thread t1 = new Thread(t);

     Thread t2 = new Thread(t);

     t1.start();//启动线程。

      t2.start();

    }

 }

 

以上两种方式,第二种优于第一种,因为采用实现方式,避免了单继承的局限性,所以一般建立使用实现Runnable接口的方式。

 

线程有六种状态:

在多线程运行中常常会出现安全问题。当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。比如说,对几个售票厅同时在卖100张票,当只剩下最后一张票时,其中一个售票厅将票资源取走,但是尚未卖出去,另一个售票厅检测到的剩余票数其实还是1,那么它也会有继续卖票的权利。如此,票就会卖多了一张。

对于这样的问题,我们要怎么解决呢?比如卖票的例子,票数是共享的数据,那么对多条操作共享数据的语句,每次只能让一个线程都执行完,才能执行别的线程这样就不会出现安全问题了。即,对于将操作共享数据的代码块加一个锁,每次开始执行就加锁,执行完解锁。Java中提供的锁就是同步代码块:

synchronized(对象)

{

需要被同步的代码

}

对象如同锁。持有锁的线程可以在同步中执行。

没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。

 

除了同步代码块,也可以采用同步函数,即将synchronized作为修饰符修饰函数。比如:public synchronizedvoid show(){}。

在同步函数中,锁就是this,调用函数的对象;而如果同步函数被静态所修饰后,使用的锁就不再是this,使用的锁是该方法所在类的字节码文件对象——类名.class。

 

以上介绍的两种处理安全问题的方法各有各的好处,使用的比较多的是同步代码块。而实现同步的前提是必须有两个或两个以上的线程而且这些线程要使用同一个锁,这一特征也是用来判别同步函数中使用的锁是什么的依据。利用this锁的同步代码块和同步函数两个线程运行,发现两个线程可以交替运行,即证明两个线程使用的是同一个锁this。

那么剩下的就是找出安全问题了,要找出安全问题,要明确哪些代码是多线程运行代码,明确共享数据,明确多线程运行代码中哪些语句是操作共享数据的。将这部分代码找出来之后就可以直接放进同步代码块中或者同步函数中。

 

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流!----------------------

 详细请查看:http://edu.csdn.net

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值