黑马程序员——10,线程

来源:互联网 发布:你有阿里云幕布么 编辑:程序博客网 时间:2024/06/06 10:44

------<ahref="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

                                               黑马程序员——10,线程

 

/*关于多线程的一些知识点:进程:正在执行的程序,每一个进程的执行都有一个执行顺序,这个顺序就是一个执行路径(控制单元)     线程:进程中的一个控制单元,线程控制进程的执行    一个进程里面至少有一个线程举一个例子:程序执行时候在堆内存建立对象,这是一个线程,而例外虚拟机还有一个不定时清空堆内存垃圾的机制,这也是一个线程最好理解的就是网上下载的东西需要分成了几个部分同时下载。(注意:这里的“同时”其实是CPU不断的快速切换执行程序才我们视觉上看到的同时执行而已,真正意义上的同时执行是没有的) 线程也是对象,所以也可以用类来描述          建立线程的第一种方式:1,定义一个类继承了Thread类2,覆盖Thread类里面的run方法3,调用线程的start方法     该方法的所用是:启动线程,调用run方法  */class Xc extends Thread //定义一个类继承了Thread类{         publicvoid run()//覆盖Thread类里面的run方法//这里的run方法仅仅是用来封装需要运行的代码         {             for(int a=0;a<90;a++)                   {                            System.out.println("输出的是a="+a);                                         }         }} class Duoxiancheng{         publicstatic void main(String[] args)         {                   Xc  b= new Xc();//建立一个线程                   b.start();//调用线程的start方法//b.run();/*这句话仅仅是一般的调用对象方法,不算是调用线程,虚拟机执行到这行也只是会把run方法执行完了之后再去执行下面的循环,这就没有调用线程!*/                   for(inta=0;a<62;a++)//主函数里面也有一段代码                   {                       System.out.println("这是主程序的"+a);                   }                   System.out.println("HelloWorld!");         }}//上面程序编译运行的结果如下:/*这是主程序的0这是主程序的1这是主程序的2这是主程序的3这是主程序的4这是主程序的5这是主程序的6这是主程序的7这是主程序的8输出的是a=0输出的是a=1输出的是a=2输出的是a=3输出的是a=4输出的是a=5输出的是a=6输出的是a=7输出的是a=8输出的是a=9输出的是a=10这是主程序的9输出的是a=11这是主程序的10输出的是a=12这是主程序的11输出的是a=13这是主程序的12输出的是a=14这是主程序的13输出的是a=15这是主程序的14输出的是a=16这是主程序的15输出的是a=17这是主程序的16输出的是a=18输出的是a=19这是主程序的17输出的是a=20这是主程序的18输出的是a=21这是主程序的19输出的是a=22这是主程序的20输出的是a=23这是主程序的21这是主程序的22输出的是a=24这是主程序的23输出的是a=25这是主程序的24这是主程序的25输出的是a=26输出的是a=27输出的是a=28输出的是a=29输出的是a=30输出的是a=31输出的是a=32输出的是a=33输出的是a=34输出的是a=35输出的是a=36这是主程序的26输出的是a=37这是主程序的27输出的是a=38这是主程序的28输出的是a=39这是主程序的29输出的是a=40这是主程序的30这是主程序的31这是主程序的32这是主程序的33这是主程序的34这是主程序的35这是主程序的36这是主程序的37这是主程序的38这是主程序的39这是主程序的40这是主程序的41这是主程序的42这是主程序的43这是主程序的44这是主程序的45这是主程序的46这是主程序的47这是主程序的48这是主程序的49这是主程序的50这是主程序的51这是主程序的52这是主程序的53这是主程序的54这是主程序的55这是主程序的56这是主程序的57这是主程序的58这是主程序的59这是主程序的60这是主程序的61Hello World!输出的是a=41输出的是a=42输出的是a=43输出的是a=44输出的是a=45输出的是a=46输出的是a=47输出的是a=48输出的是a=49输出的是a=50输出的是a=51输出的是a=52输出的是a=53输出的是a=54输出的是a=55输出的是a=56输出的是a=57输出的是a=58输出的是a=59输出的是a=60输出的是a=61输出的是a=62输出的是a=63输出的是a=64输出的是a=65输出的是a=66输出的是a=67输出的是a=68输出的是a=69输出的是a=70输出的是a=71输出的是a=72输出的是a=73输出的是a=74输出的是a=75输出的是a=76输出的是a=77输出的是a=78输出的是a=79输出的是a=80输出的是a=81输出的是a=82输出的是a=83输出的是a=84输出的是a=85输出的是a=86输出的是a=87输出的是a=88输出的是a=89*/
 

//——————分割线————

每一次运行的结果都是不一样的

多个线程都在抢夺CPU的执行权,CPU执行到谁,谁就执行

某一个时刻只能有一个程序在运行(多核除外)

CPU实际上就是在做着快速的切换执行着不同的程序,

还有通过上面编译运行结果可以知道就算是“这是主程序的...”执行完了,但是虚拟机还是会把剩余的“输出的是a=...”执行完

//——————分割线————

 

多线程的运行状态介绍:

被创建,运行,冻结,消亡,阻塞(临时)状态

阻塞(临时)状态:具备运行资格却没有执行权

冻结:放弃执行资格

 

1,先是被创建,然后通过start()达到运行状态;,

2,在运行状态的时候也有可能通过stop()或者run方法结束而消亡;

3,程序在运行状态时有可能因为CPU的切换而需要临时等待,

   此时会处于阻塞(临时)状态;

4,程序在运行时也可能通过sleep(时间)形成冻结状态,

   也可以通过sleep时间到而恢复运行状态;

  运行到冻结状态之间的变换除了通过sleep关键字达成之外,

   运行状态还可以通过wait()达到冻结状态,再通过notify()恢复到运行状态;

5,不过,有时候从冻结状态恢复之后由于CPU切换到其他程序也可能会处于临时状态

*/

——————分割线——————

/*以下是多线程的一些小知识点*/class Xca  extends Thread{    private String name;          Xca(String name )         {            this.name = name ;          }         publicvoid run()         {             for(int a=1;a<5;a++)                   {                      System.out.println(this.getName()+" Xc里面的run...");                   }         }}  class Xiancheng2{         publicstatic void main(String[] args)         {                   Xca  a= new Xca("例子");                   Xca  b= new Xca("例子");       a.start();                   b.start();     /*        //这里特别说明       Thread  c= new Thraed();       c.start();      //这一段代码编译运行起来是没有东西显示的,因为Thread类里面的run方法没有东西*/                   System.out.println("HelloWorld!");         }}/*编译运行结果是:Thread-0 Xc里面的run...Thread-1 Xc里面的run...Thread-1 Xc里面的run...Thread-1 Xc里面的run...Thread-1 Xc里面的run...Hello World!Thread-0 Xc里面的run...Thread-0 Xc里面的run...Thread-0 Xc里面的run... 这就是说明了线程都是有自己默认名字Thread-编号,这个编号从0开始而且还有自己获取名字的getName()方法*/

————————分割线——————

 

 

class Xca  extends Thread{    private String name;          Xca(String name )         {            this.name = name ;          }         publicvoid run()         {             for(int a=1;a<5;a++)                   {                       System.out.println("调用this.getName()————"+this.getName());                       System.out.println("调用Thread.currentThread().getName() ————"+Thread.currentThread().getName());                   //Thread.currentThread()作用是获取当前线程对象的名称,在这里的作用和this一样         System.out.println("调用Thread.currentThread()————"+Thread.currentThread());                                     }          }} class Xiancheng3{         publicstatic void main(String[] args)         {         Xca  a= new Xca("例子");        a.start();         }}/*以上程序编译运行结果:调用this.getName()————Thread-0调用Thread.currentThread().getName()————Thread-0调用Thread.currentThread()————Thread[Thread-0,5,main]调用this.getName()————Thread-0调用Thread.currentThread().getName()————Thread-0调用Thread.currentThread()————Thread[Thread-0,5,main]调用this.getName()————Thread-0调用Thread.currentThread().getName()————Thread-0调用Thread.currentThread()————Thread[Thread-0,5,main]调用this.getName()————Thread-0调用Thread.currentThread().getName()————Thread-0调用Thread.currentThread()————Thread[Thread-0,5,main]*/

————————分割线——————

 

 

/*多线程的售票例子四个窗口同时卖票,票数总共20张*/class Shoupiao extends Thread                      {         privatestatic int piao=20;//把票数设定为静态    public void run()          {              while (true)              {                             if(  piao>0   )                             {                                  System.out.println(Thread.currentThread().getName()+"————票数"+piao--  );                                  }              }          }} class Xiancheng4{         publicstatic void main(String[] args)         {        Shoupiao a=new Shoupiao();       Shoupiao  b=new Shoupiao();                   Shoupiao  c=new Shoupiao();                   Shoupiao  d=new Shoupiao();                   a.start();       b.start();                   c.start();                   d.start();                   /*                   //其实还有另外一种方式来实现     Shoupiao  a=new Shoupiao();                   a.start();       a.start();                   a.start();             a.start();                                     //但是这样编译运行也会提示出线程状态异常,既然一条线程已经开始start()了                    //  那么就没有必要再开始start()一次了                                       */                   System.out.println("HelloWorld!");         }}/*以上程序编译运行结果是:(特别说明:因为while (true)这句话的关系,最后要按Ctrl+c按键才停下虚拟机,否则会耗费很多资源)Thread-0————票数20Thread-0————票数18Hello World!Thread-3————票数15Thread-1————票数19Thread-3————票数14Thread-0————票数16Thread-2————票数17Thread-0————票数11Thread-3————票数12Thread-1————票数13Thread-3————票数8Thread-0————票数9Thread-2————票数10Thread-0————票数5Thread-3————票数6Thread-1————票数7Thread-3————票数2Thread-0————票数3Thread-2————票数4Thread-1————票数1 */

——————分割线——————

 

/*使用另外一种方式建立线程:实现Runnable接口这种方式建立线程是最为方便的,因为如果使用第一种方式建立线程的话,遇到一些已经有自己父类的类就没有办法让其再继承一个父类因为Java对于类与类之间仅仅是支持单继承的所以这种方式是最为常用的建立线程方式  */class Shoupiao implements Runnable   //定义一个类实现Runable接口               {         private  int piao=20;//这里就不需要static,因为这里针对的只有一个对象    public void run()//覆盖Runnable接口的run方法          {              while (true)/*特别说明:因为 while (true)这句话的关系,最后要按Ctrl+c按键才停下虚拟机,否则会耗费很多资源)*/              {                             if(  piao>0   )                             {                                  System.out.println(Thread.currentThread().getName()+"————票数"+piao--  );                                  }              }          }} Class  Xiancheng5{         publicstatic void main(String[] args)         {                   Shoupiao  a=new Shoupiao();//这个不是线程                                       Threadb1=new Thread(a);                         Thread b2=new Thread(a);                                     Threadb3=new Thread(a);                                     Threadb4=new Thread(a);                   //通过Thread类建立线程对象                   //将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数                    b1.start();       b2.start();                   b3.start();                   b4.start();       //调用Thread类的start方法开启线程并调用Runnable接口子类的run方法                     System.out.println("HelloWorld!");         }}/*以上程序编译运行的结果如下:Thread-0————票数20Thread-3————票数17Thread-3————票数15Thread-3————票数14Thread-1————票数19Thread-2————票数18Thread-2————票数11Thread-2————票数10Thread-2————票数9Thread-2————票数8Thread-2————票数7Thread-2————票数6Thread-2————票数5Thread-2————票数4Hello World!Thread-2————票数3Thread-1————票数12Thread-3————票数13Thread-0————票数16Thread-1————票数1Thread-2————票数2*/

——————分割线——————

 

/*   多线程的安全隐患*/ class Shoupiao implements Runnable       {         private  int piao=20;    public void run()          {              while (true)//特别说明:因为 while (true)这句话的关系,最后要按Ctrl+c按键才停下虚拟机,否则会耗费很多资源)                    {                             if(  piao>0   )                             {                                      try                                      {                                               Thread.sleep(12);//我们模拟可能出现的安全隐患                                               //Thread.sleep(12);//该方法是静态方法所以可以直接类名Thread调用                             /*                                 强制程序处于12毫秒的冻结状态,12毫秒后又恢复                                      因为如果是某个时刻piao=1了,所有线程执行到这里都会陷入冻结状态                                      12毫秒后,某一个线程又开始执行下去,打印的票数为1                                                第二个线程又开始执行下去,打印的票数为0                                                           第三个线程又开始执行下去,打印的票数为-1                                     这种情况就是安全隐患了                            */                                      }                                      catch (Exception e) {}                                    System.out.println(Thread.currentThread().getName()+"————票数"+piao--  );                                  }              }          }} class Xiancheng6{         publicstatic void main(String[] args)         {                   Shoupiao  a=new Shoupiao();                                       Threadb1=new Thread(a);                         Thread b2=new Thread(a);                                     Threadb3=new Thread(a);                                     Threadb4=new Thread(a);                   b1.start();       b2.start();                   b3.start();                   b4.start();                   System.out.println("HelloWorld!");         }}/*以上代码编译运行结果:Hello World!Thread-3————票数20Thread-2————票数18Thread-1————票数19Thread-0————票数20Thread-3————票数17Thread-0————票数14Thread-1————票数15Thread-2————票数16Thread-2————票数13Thread-1————票数12Thread-0————票数11Thread-3————票数10Thread-2————票数9Thread-0————票数8Thread-1————票数7Thread-3————票数6Thread-2————票数5Thread-0————票数4Thread-3————票数2Thread-1————票数3Thread-2————票数1Thread-1————票数0Thread-3————票数-2Thread-0————票数-1这里就可以看出出问题了*/

 

/*

出现问题的原因:

多条语句在操作同一个线程共享数据时候,一个线程对多条语句执行了一部分还没有执行完

另外一条线程就参与进来执行导致共享数据错误

 

解决的办法:

synchronized(对象)

{

    需要同步的代码;

}

*/

 

 

/*   以下是多线程的安全隐患的解决方式*/class  Shoupiao implements Runnable        {private  int piao=200;Object obj=new Object();//直接建立Object对象更加方便     public void run() {     while (true)//特别说明:因为 while (true)这句话的关系,最后要按Ctrl+c按键才停下虚拟机,否则会耗费很多资源) {    synchronized (obj)//obj就相当于锁,只有拥有所的线程才可以进来执行同步代码块,执行完之后再释放锁,后面一个线程才有机会得到锁进来执行同步代码块//没有锁的线程绝对不能执行同步代码块//虽然这种办法解决了安全隐患,但是每一个线程进来都要做一个锁的判断,如果线程过多会消耗资源,这也是一个弊端{  if(   piao>0   )     { try{Thread.sleep(12); } catch (Exception e) {}                 System.out.println(Thread.currentThread().getName()+"————票数"+piao--  );  } }     } }} class Xiancheng7{public static void main(String[] args) {Shoupiao  a=new Shoupiao(); Thread b1=new Thread(a);        Thread b2=new Thread(a);Thread b3=new Thread(a);Thread b4=new Thread(a);b1.start();        b2.start();b3.start();b4.start();System.out.println("Hello World!");}}/*以上代码编译运行结果:Hello World!Thread-0————票数200Thread-0————票数199Thread-0————票数198Thread-0————票数197Thread-0————票数196Thread-0————票数195Thread-0————票数194Thread-0————票数193Thread-0————票数192Thread-0————票数191Thread-0————票数190Thread-0————票数189Thread-0————票数188Thread-0————票数187Thread-0————票数186Thread-0————票数185Thread-0————票数184Thread-0————票数183Thread-0————票数182Thread-0————票数181Thread-0————票数180Thread-0————票数179Thread-0————票数178Thread-0————票数177Thread-0————票数176Thread-3————票数175Thread-3————票数174Thread-3————票数173Thread-3————票数172Thread-3————票数171Thread-3————票数170Thread-3————票数169Thread-3————票数168Thread-3————票数167Thread-3————票数166Thread-3————票数165Thread-3————票数164Thread-3————票数163Thread-3————票数162Thread-3————票数161Thread-3————票数160Thread-3————票数159Thread-3————票数158Thread-3————票数157Thread-3————票数156Thread-3————票数155Thread-3————票数154Thread-3————票数153Thread-3————票数152Thread-3————票数151Thread-3————票数150Thread-3————票数149Thread-3————票数148Thread-3————票数147Thread-3————票数146Thread-3————票数145Thread-3————票数144Thread-3————票数143Thread-3————票数142Thread-3————票数141Thread-3————票数140Thread-3————票数139Thread-3————票数138Thread-3————票数137Thread-3————票数136Thread-3————票数135Thread-3————票数134Thread-3————票数133Thread-3————票数132Thread-3————票数131Thread-3————票数130Thread-3————票数129Thread-3————票数128Thread-3————票数127Thread-3————票数126Thread-3————票数125Thread-3————票数124Thread-3————票数123Thread-3————票数122Thread-3————票数121Thread-3————票数120Thread-3————票数119Thread-3————票数118Thread-3————票数117Thread-3————票数116Thread-3————票数115Thread-3————票数114Thread-3————票数113Thread-3————票数112Thread-3————票数111Thread-3————票数110Thread-3————票数109Thread-3————票数108Thread-3————票数107Thread-3————票数106Thread-3————票数105Thread-3————票数104Thread-3————票数103Thread-3————票数102Thread-3————票数101Thread-3————票数100Thread-3————票数99Thread-3————票数98Thread-3————票数97Thread-3————票数96Thread-3————票数95Thread-3————票数94Thread-3————票数93Thread-3————票数92Thread-3————票数91Thread-3————票数90Thread-3————票数89Thread-3————票数88Thread-3————票数87Thread-3————票数86Thread-3————票数85Thread-3————票数84Thread-3————票数83Thread-3————票数82Thread-3————票数81Thread-3————票数80Thread-3————票数79Thread-3————票数78Thread-3————票数77Thread-3————票数76Thread-3————票数75Thread-3————票数74Thread-3————票数73Thread-3————票数72Thread-3————票数71Thread-3————票数70Thread-3————票数69Thread-3————票数68Thread-3————票数67Thread-3————票数66Thread-3————票数65Thread-3————票数64Thread-3————票数63Thread-3————票数62Thread-3————票数61Thread-3————票数60Thread-3————票数59Thread-3————票数58Thread-3————票数57Thread-3————票数56Thread-3————票数55Thread-3————票数54Thread-3————票数53Thread-3————票数52Thread-3————票数51Thread-3————票数50Thread-3————票数49Thread-3————票数48Thread-2————票数47Thread-2————票数46Thread-2————票数45Thread-2————票数44Thread-2————票数43Thread-2————票数42Thread-2————票数41Thread-2————票数40Thread-2————票数39Thread-2————票数38Thread-2————票数37Thread-2————票数36Thread-2————票数35Thread-2————票数34Thread-2————票数33Thread-2————票数32Thread-2————票数31Thread-2————票数30Thread-2————票数29Thread-2————票数28Thread-2————票数27Thread-2————票数26Thread-2————票数25Thread-2————票数24Thread-2————票数23Thread-2————票数22Thread-2————票数21Thread-2————票数20Thread-2————票数19Thread-2————票数18Thread-2————票数17Thread-2————票数16Thread-2————票数15Thread-2————票数14Thread-2————票数13Thread-2————票数12Thread-2————票数11Thread-2————票数10Thread-2————票数9Thread-2————票数8Thread-2————票数7Thread-2————票数6Thread-2————票数5Thread-2————票数4Thread-2————票数3Thread-2————票数2Thread-2————票数1*/

0 0
原创粉丝点击