你的位置:首页 > Java教程

[Java教程]黑马程序员系列第一篇 多线程(1)


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

 

(前言:本篇文章主要依据毕向东老师的课程视频整理而成,如要详细学习,请观看毕老师视频  百度网盘链接地址:http://pan.baidu.com/s/1sjQRHDz)

 

目录:一、线程的两种创建方式        二、线程的五种状态、线程操作中常用的方法        三、多线程安全  四、使用同步的弊端         五、单例设计模式中的多线程(面试重点)

 

一、线程的两种创建方式

      1、实现Runnable接口(主流)

          代码示例:

 1 public class ThreadTest{ 2    3   public static void main(String[] args) throws InterruptedException{ 4    ThreadImple ti=new ThreadImple(); 5    Thread thread=new Thread(ti); 6     7    thread.start(); 8 } 9 }10 class ThreadImple implements Runnable {11 12   @Override13   public void run() {14     for(int i=0;i<60;i++)15     System.out.println("thread implements runnable..."+i);16   }17 }

      2、继承Thread类

     

public class ThreadTest{    public static void main(String[] args) throws InterruptedException{   ThreadExtends ti=new ThreadExtends();      ti.start();}} class ThreadExtends extends Thread {  public void run() {    for(int i=0;i<60;i++)    System.out.println("extend thread class..."+i);  }}

 

      3、两种创建方式的区别

            实现方式的运行代码存放在接口子类的run方法中;实现方式避免了单继承的局限性,建议使用

        继承方式的运行代码存放在Thread子类的run方法中

   

二、线程的五种状态    线程操作中常用的方法

 

 

三、多线程安全

        问题:一个线程操作多条语句来共享数据时,一个线程对多条语句只执行了一部分,另一个线程便参与进来执行了,导致共享数据出错。

        如何寻找问题:  1、明确哪些代码示多线程运行代码     2、明确共享数据     3、明确多线程运行代码中哪些语句是操作共享数据的。

  解决办法:同步代码块:

             Synchronized( 锁 ){

                  需要被同步的代码;

             }

                       同步函数:在函数前加synchronized修饰符。

  使用同步要满足三个前提:1、必须有两个或两个以上线程  2、必须是多个线程使用同一个锁

  弊端:每次执行时都要判断锁,浪费资源。

  普通同步函数的锁是this ,静态函数的锁是其所在文件字节码对象(.class)

      简单模拟售票代码:

 1 /* 2 程序一共创建三个线程模拟三个售票窗口  ticket=100将票号设为1-100 我们希望票号不重复 3 遗憾的是结果会出现票号为负数、相同票号的问题   也就是我们要讲到的线程不安全问题 4 */ 5 public class SaleTicketUnsafe { 6  7   public static void main(String[] args) { 8  9     Ticket ticket=new Ticket();10     11     new Thread(ticket).start();12     new Thread(ticket).start();13     new Thread(ticket).start();14     15   }16 17 }18 class Ticket implements Runnable{19  20  private int ticket=100;21  public void run(){22   while(true){23     if(ticket>0){24       try {25         Thread.sleep(10);//线程出错概率不是很大,所以要让线程休眠sleep()来将问题暴露出来26       } catch (InterruptedException e) {27         // TODO Auto-generated catch block28         e.printStackTrace();29       }30     System.out.println(Thread.currentThread().getName()+"售票口出售---车票号:"+ticket--);31     }32   }33     34   }35 }

     使用同步代码块的方式改进后的程序

   

 1 /*同步代码块的方式解决了问题*/ 2 public class SaleTicketSafe { 3  4   public static void main(String[] args) { 5     Tickets ticket=new Tickets(); 6      7     new Thread(ticket).start(); 8     new Thread(ticket).start(); 9     new Thread(ticket).start();10   }11 12 }13 class Tickets implements Runnable{14   15   private int ticket=100;16   Object obj=new Object();17   @Override18   public void run() {19     while(true){20       synchronized(obj){//同步代码块21       if(ticket>0){22         try {23           Thread.sleep(10);24           } catch (InterruptedException e) {25           // TODO Auto-generated catch block26           e.printStackTrace();27         }28       System.out.println(Thread.currentThread().getName()+"售票口出售---车票号:"+ticket--);29       }  30       }31     }32   }33   34 }

 

 

四、使用同步会出现死锁情况(面试时会要求写一个死锁程序)

      问题:多线程各自持有不同的锁没释放,而又彼此需要对方的锁。

    原因:同步中嵌套同步,而它们的锁却不同

 一个简单的死锁程序:

 1 public class DieLock { 2    3  public static void main(String[] args){ 4   //开启两个线程测试 5   Thread t1=new Thread(new Test(true)); 6   t1.start(); 7   Thread t2=new Thread(new Test(false));   8   t2.start();   9   }10 }11 class Test implements Runnable{12   boolean flag;13   public Test(boolean f){14     this.flag=f;15   }16   @Override17   public void run() {18     if(flag){19       while(true){20       synchronized(Lock.lockb){21         System.out.println("if locka");22         synchronized(Lock.locka){23           System.out.println("if lockb");  24         }25       }26       }27     }else{28       while(true){29       synchronized(Lock.locka){30         System.out.println("else locka");31         synchronized(Lock.lockb){32           System.out.println("else lockb");  33         }34       }35       }36     }    37 }38   //单独定义两个不同的锁39 static class Lock{40   static Object locka=new Object();41   static Object lockb=new Object();42 }    43 }

 

五、单例设计模式中的多线程(面试重点)

       饿汉式、懒汉式(是线程不安全的,需要同步)

       将懒汉式同步有两种方式:

        1、下面代码中在getInstance方法前用synchronized修饰,通过同步函数来解决,每次都要同步比较消耗资源   

        2、就是注释中用同步块的方式,用双重判断(s==null)只需同步一次,避免多消耗资源,推荐使用

public class Single{  public static void main(String[] args){        Singlel s=Singlel.getInstance();      }}//懒汉式 class Singlel extends Single{   private Singlel(){}  private static Singlel s=null;    public static synchronized Singlel getInstance(){    if(s==null)     s=new Singlel();//    if(s==null){//      synchronized(Singlel.class){  方法二、双重判断 ,提高效率//        if(s==null)//          s=new Singlel();//      }//    }    return s;  }} //饿汉式 class Singlee extends Single{   private Singlee(){}  private static Singlee s=new Singlee();    public static Singlee getInstance(){    return s;  }  }

       

       初学者难免错误,欢迎评判指教,持续更正ing...........

 

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