• 黑马程序员系列第一篇 多线程(1)


     

    (前言:本篇文章主要依据毕向东老师的课程视频整理而成,如要详细学习,请观看毕老师视频  百度网盘链接地址: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     @Override
    13     public void run() {
    14         for(int i=0;i<60;i++)
    15         System.out.println("thread implements runnable..."+i);
    16     }
    17 }

          2、继承Thread类

         

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

          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 block
    28                 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     @Override
    18     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 block
    26                     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     @Override
    17     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)只需同步一次,避免多消耗资源,推荐使用

     1 public class Single{
     2     public static void main(String[] args){
     3         
     4         Singlel s=Singlel.getInstance();
     5         
     6     }
     7 }
     8 //懒汉式
     9  class Singlel extends Single{
    10 
    11      private Singlel(){}
    12     private static Singlel s=null;
    13     
    14     public static synchronized Singlel getInstance(){
    15         if(s==null)
    16           s=new Singlel();
    17 //        if(s==null){
    18 //            synchronized(Singlel.class){    方法二、双重判断 ,提高效率
    19 //                if(s==null)
    20 //                    s=new Singlel();
    21 //            }
    22 //        }
    23         return s;
    24     }
    25 }
    26  //饿汉式
    27  class Singlee extends Single{
    28      private  Singlee(){}
    29     private static Singlee s=new Singlee();
    30     
    31     public static Singlee getInstance(){
    32         return s;
    33     }
    34     
    35 }

           

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

  • 相关阅读:
    webpack4入门配置
    RequireJs的理解
    js一次控制 多个style样式
    vue中封装一个全局的弹窗js
    地理位置索引 2d索引
    索引属性 稀疏索引,定时索引
    索引属性 unique指定
    索引属性 name指定
    mongodb索引 全文索引使用限制
    mongodb索引 全文索引之相似度查询
  • 原文地址:https://www.cnblogs.com/blueFlowers/p/4948332.html
Copyright © 2020-2023  润新知