黑马程序员_多线程与死锁

------- android培训java培训、期待与您交流! ----------

 

一、线程的创建

1、继承Thread类

创建步骤:
1、定义类继承Thread
2、复写Thread类中的run方法
3、调用线程的start方法
此方法有两个作用:
启动线程
调用run()方法

class Demo extends Thread//定义类继承Thread { public void run()//复写run()方法 { for(int x=0; x<60; x++) System.out.println("Demo run()---"+x); } } class ThreadDemo { public static void main(String[] args) { Demo d = new Demo();//创建一个线程 d.start();//开启线程,并调用线程的run()方法

for(int x=0; x<60; x++) System.out.println("Hello Thread!---"+x); } }

程序运行结果如下:
黑马程序员_多线程 - freedomheaven - freedomheaven的博客
 
运行结果每一次都不同。
因为多个下次都要获取CPU的执行权,CPU执行到谁,谁就运行。
但是在某一时刻,只能有一个程序在运行。(多核除外)
多线程的一个特性,随机性。

2、实现Runnable接口

/* 需求:简单的卖票程序,多个窗口同是卖票。

创建线程的第二种方式:实现Runnable接口

步骤: 1、定义类实现Runnable接口 2、覆盖Runnable接口中的run方法。 将线程要运行的代码存放在该run方法中。 3、通过Thread类建立线程对象。 4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。 5、调用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--); } } } } class TicketDemo { public static void main(String[] args) { Ticket t = new Ticket();

Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } }

程序运行结果如下:
黑马程序员_多线程 - freedomheaven - freedomheaven的博客

3、两种方法对比


实现方式和继承方式有什么区别?

实现方式好处:避免了单继承的局限性。
在定义线程时,建议使用实现方式。

两种方式区别:
继承Thread:线程代码存放在Thread子类run方法中。
实现Runnable:线程代码存放在接口的子类的run方法中。

二、多线程的安全问题

1、通过分析上述程序,发现存在安全隐患,可以通过代码进行验证。

class Ticket implements Runnable { private int tick = 100; public synchronized void run() { while (true) { if(tick>0) { //因为继承了接口,而接口中没有异常的抛出,所以只能try try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"---sale : "+tick--); } } } }

修改后运行结果出现以下情况:
              
              
黑马程序员_多线程 - freedomheaven - freedomheaven的博客
出现问题原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还未执行完,另一个线程就进入执行,从而导致共享数据出错。
2、JAVA对多线程安全问题有专业解决方式:同步代码块。 synchronized(对象) {  需要被同步的代码 }

具体代码如下:

 

class Ticket implements Runnable {  //Object obj = new Object();    private int tick = 1000;  public void run()  {   while (true)   {    synchronized(this)    {     if(tick>0)     {      //因为继承了接口,而接口中没有异常的抛出,所以只能try      try{Thread.sleep(10);}catch(Exception e){}      System.out.println(Thread.currentThread().getName()+"---sale  : "+tick--);     }    }   }  } } class TicketDemo2 {  public static void main(String[] args)  {   Ticket t = new Ticket();

 

  Thread t1 = new Thread(t);   Thread t2 = new Thread(t);   Thread t3 = new Thread(t);   Thread t4 = new Thread(t);   Thread t5 = new Thread(t);      t1.start();   t2.start();   t3.start();   t4.start();   t5.start();     } }

 
             

代码修改后,运行结果中未出现为0等错误情况。

好像是CPU的缘故,在票数1000的时候,只能看到一个线程。当票数为10000的时候,方可看到其他线程运行的情况。

 

3、单例设计模式

 

/* 单例设计模式

 

*/ //饿汗式 class Single {  private static final Single s = new Single();  private Single(){}  public static Single getInstance()  {   return s;  } }

 

//懒汉式

//延迟加载单例模式 class Single {  private static Single s = null;  private Single(){}  public static Single getInstance()  {   synchronized(Single.class)//通过锁确保程序在多线程访问时运行安全   {    if(s==null)     s = new Single();   }   return s;  } }

 

发现懒汉式中,如果有一个线程进入锁中,其它线程只能等待,会导致程序效率低,继续对其进行完善。

class Single {  private static Single s = null;  private Single(){}  public static Single getInstance()  {   if(s==null)//进行判断,如果不为空,就不需要等待锁。   {    synchronized(Single.class)    {     if(s==null)      s = new Single();    }   }   return s;  } }

 
             

 

 

三、死锁的探讨
 

/* 死锁形成探讨 */ class Test implements Runnable {  private boolean flag;  Test(boolean flag)//建立标识,让两个线程分别运行。  {   this.flag = flag;  }  public void run()//锁相互嵌套,形成各自占用资源,同时需要对方资源。  {   if (flag)   {    synchronized(MyLock.LockA)    {     System.out.println("if LockA");     synchronized(MyLock.LockB)     {      System.out.println("if LockB");     }    }   }   else   {    synchronized(MyLock.LockB)    {     System.out.println("else LockB");     synchronized(MyLock.LockA)     {      System.out.println("else LockA");     }    }   }  } } class MyLock//创建两个锁 {  static Object LockA = new Object();  static Object LockB = new Object(); } class DeadLockDemo {  public static void main(String[] args)  {   Thread t1 = new Thread(new Test(true));//创建线程t1   Thread t2 = new Thread(new Test(false));//创建线程t2

  t1.start();   t2.start();  } }

程序运行结果如下:
               
               
黑马程序员_多线程 - freedomheaven - freedomheaven的博客
可见:两个线程分别只运行了第一输出语句,便形成了死锁。
 

----------- android培训java培训、期待与您交流! --------------   

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值