黑马程序员——10,线程

------<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
这是主程序的61
Hello 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————票数20
Thread-0————票数18
Hello World!
Thread-3————票数15
Thread-1————票数19
Thread-3————票数14
Thread-0————票数16
Thread-2————票数17
Thread-0————票数11
Thread-3————票数12
Thread-1————票数13
Thread-3————票数8
Thread-0————票数9
Thread-2————票数10
Thread-0————票数5
Thread-3————票数6
Thread-1————票数7
Thread-3————票数2
Thread-0————票数3
Thread-2————票数4
Thread-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————票数20
Thread-3————票数17
Thread-3————票数15
Thread-3————票数14
Thread-1————票数19
Thread-2————票数18
Thread-2————票数11
Thread-2————票数10
Thread-2————票数9
Thread-2————票数8
Thread-2————票数7
Thread-2————票数6
Thread-2————票数5
Thread-2————票数4
Hello World!
Thread-2————票数3
Thread-1————票数12
Thread-3————票数13
Thread-0————票数16
Thread-1————票数1
Thread-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————票数20
Thread-2————票数18
Thread-1————票数19
Thread-0————票数20
Thread-3————票数17
Thread-0————票数14
Thread-1————票数15
Thread-2————票数16
Thread-2————票数13
Thread-1————票数12
Thread-0————票数11
Thread-3————票数10
Thread-2————票数9
Thread-0————票数8
Thread-1————票数7
Thread-3————票数6
Thread-2————票数5
Thread-0————票数4
Thread-3————票数2
Thread-1————票数3
Thread-2————票数1
Thread-1————票数0
Thread-3————票数-2
Thread-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————票数200
Thread-0————票数199
Thread-0————票数198
Thread-0————票数197
Thread-0————票数196
Thread-0————票数195
Thread-0————票数194
Thread-0————票数193
Thread-0————票数192
Thread-0————票数191
Thread-0————票数190
Thread-0————票数189
Thread-0————票数188
Thread-0————票数187
Thread-0————票数186
Thread-0————票数185
Thread-0————票数184
Thread-0————票数183
Thread-0————票数182
Thread-0————票数181
Thread-0————票数180
Thread-0————票数179
Thread-0————票数178
Thread-0————票数177
Thread-0————票数176
Thread-3————票数175
Thread-3————票数174
Thread-3————票数173
Thread-3————票数172
Thread-3————票数171
Thread-3————票数170
Thread-3————票数169
Thread-3————票数168
Thread-3————票数167
Thread-3————票数166
Thread-3————票数165
Thread-3————票数164
Thread-3————票数163
Thread-3————票数162
Thread-3————票数161
Thread-3————票数160
Thread-3————票数159
Thread-3————票数158
Thread-3————票数157
Thread-3————票数156
Thread-3————票数155
Thread-3————票数154
Thread-3————票数153
Thread-3————票数152
Thread-3————票数151
Thread-3————票数150
Thread-3————票数149
Thread-3————票数148
Thread-3————票数147
Thread-3————票数146
Thread-3————票数145
Thread-3————票数144
Thread-3————票数143
Thread-3————票数142
Thread-3————票数141
Thread-3————票数140
Thread-3————票数139
Thread-3————票数138
Thread-3————票数137
Thread-3————票数136
Thread-3————票数135
Thread-3————票数134
Thread-3————票数133
Thread-3————票数132
Thread-3————票数131
Thread-3————票数130
Thread-3————票数129
Thread-3————票数128
Thread-3————票数127
Thread-3————票数126
Thread-3————票数125
Thread-3————票数124
Thread-3————票数123
Thread-3————票数122
Thread-3————票数121
Thread-3————票数120
Thread-3————票数119
Thread-3————票数118
Thread-3————票数117
Thread-3————票数116
Thread-3————票数115
Thread-3————票数114
Thread-3————票数113
Thread-3————票数112
Thread-3————票数111
Thread-3————票数110
Thread-3————票数109
Thread-3————票数108
Thread-3————票数107
Thread-3————票数106
Thread-3————票数105
Thread-3————票数104
Thread-3————票数103
Thread-3————票数102
Thread-3————票数101
Thread-3————票数100
Thread-3————票数99
Thread-3————票数98
Thread-3————票数97
Thread-3————票数96
Thread-3————票数95
Thread-3————票数94
Thread-3————票数93
Thread-3————票数92
Thread-3————票数91
Thread-3————票数90
Thread-3————票数89
Thread-3————票数88
Thread-3————票数87
Thread-3————票数86
Thread-3————票数85
Thread-3————票数84
Thread-3————票数83
Thread-3————票数82
Thread-3————票数81
Thread-3————票数80
Thread-3————票数79
Thread-3————票数78
Thread-3————票数77
Thread-3————票数76
Thread-3————票数75
Thread-3————票数74
Thread-3————票数73
Thread-3————票数72
Thread-3————票数71
Thread-3————票数70
Thread-3————票数69
Thread-3————票数68
Thread-3————票数67
Thread-3————票数66
Thread-3————票数65
Thread-3————票数64
Thread-3————票数63
Thread-3————票数62
Thread-3————票数61
Thread-3————票数60
Thread-3————票数59
Thread-3————票数58
Thread-3————票数57
Thread-3————票数56
Thread-3————票数55
Thread-3————票数54
Thread-3————票数53
Thread-3————票数52
Thread-3————票数51
Thread-3————票数50
Thread-3————票数49
Thread-3————票数48
Thread-2————票数47
Thread-2————票数46
Thread-2————票数45
Thread-2————票数44
Thread-2————票数43
Thread-2————票数42
Thread-2————票数41
Thread-2————票数40
Thread-2————票数39
Thread-2————票数38
Thread-2————票数37
Thread-2————票数36
Thread-2————票数35
Thread-2————票数34
Thread-2————票数33
Thread-2————票数32
Thread-2————票数31
Thread-2————票数30
Thread-2————票数29
Thread-2————票数28
Thread-2————票数27
Thread-2————票数26
Thread-2————票数25
Thread-2————票数24
Thread-2————票数23
Thread-2————票数22
Thread-2————票数21
Thread-2————票数20
Thread-2————票数19
Thread-2————票数18
Thread-2————票数17
Thread-2————票数16
Thread-2————票数15
Thread-2————票数14
Thread-2————票数13
Thread-2————票数12
Thread-2————票数11
Thread-2————票数10
Thread-2————票数9
Thread-2————票数8
Thread-2————票数7
Thread-2————票数6
Thread-2————票数5
Thread-2————票数4
Thread-2————票数3
Thread-2————票数2
Thread-2————票数1
*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值