黑马程序员——Java基础---多线程

来源:互联网 发布:sqlalchemy 原生sql 编辑:程序博客网 时间:2024/06/06 12:49

-----------android培训java培训、java学习型技术博客、期待与您交流!------------ 

 

一、多线程概述

        要理解多线程,就必须理解线程。而要理解线程,就必须知道进程。

1、 进程

        是一个正在执行的程序。

        每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。

2、线程

         就是进程中的一个独立的控制单元。线程在控制着进程的执行。只要进程中有一个线程在执行,进程就不会结束。

        一个进程中至少有一个线程。

3、多线程

        java虚拟机启动的时候会有一个java.exe的执行程序,也就是一个进程。该进程中至少有一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。JVM启动除了执行一个主线程,还有负责垃圾回收机制的线程。像种在一个进程中有多个线程执行的方式,就叫做多线程。

4、多线程存在的意义

        多线程的出现能让程序产生同时运行效果。可以提高程序执行效率。

         例如:在java.exe进程执行主线程时,如果程序代码特别多,在堆内存中产生了很多对象,而同时对象调用完后,就成了垃圾。如果垃圾过多就有可能是堆内存出现内存不足的现象,只是如果只有一个线程工作的话,程序的执行将会很低效。而如果有另一个线程帮助处理的话,如垃圾回收机制线程来帮助回收垃圾的话,程序的运行将变得更有效率。

5、计算机CPU的运行原理

         我们电脑上有很多的程序在同时进行,就好像cpu在同时处理这所以程序一样。但是,在一个时刻,单核的cpu只能运行一个程序。而我们看到的同时运行效果,只是cpu在多个进程间做着快速切换动作。

         cpu执行哪个程序,是毫无规律性的。这也是多线程的一个特性:随机性。哪个线程被cpu执行,或者说抢到了cpu的执行权,哪个线程就执行。而cpu不会只执行一个,当执行一个一会后,又会去执行另一个,或者说另一个抢走了cpu的执行权。至于究竟是怎么样执行的,只能由cpu决定。

 

二、创建线程的方式

        创建线程共有两种方式:继承方式和实现方式(简单的说)。

1、 继承方式

        通过查找java的帮助文档API,我们发现java中已经提供了对线程这类事物的描述的类——Thread类。这第一种方式就是通过继承Thread类,然后复写其run方法的方式来创建线程。

创建步骤:

        a,定义类继承Thread

        b,复写Thread中的run方法。

             目的:将自定义代码存储在run方法中,让线程运行。

        c,创建定义类的实例对象。相当于创建一个线程。

        d,用该对象调用线程的start方法。该方法的作用是:启动线程,调用run方法。

注:如果对象直接调用run方法,等同于只有一个线程在执行,自定义的线程并没有启动。

覆盖run方法的原因:

        Thread类用于描述线程。该类就定义了一个功能,用于存储线程要执行的代码。该存储功能就run方法。也就是说,Thread类中的run方法,用于存储线程要运行的代码。

程序示例:

[java] view plaincopy
  1. /* 
  2. 小练习 
  3. 创建两线程,和主线程交替运行。 
  4. */  
  5.   
  6. //创建线程Test  
  7. class Test extends Thread  
  8. {  
  9. //  private String name;  
  10.     Test(String name)  
  11.     {  
  12.         super(name);  
  13. //      this.name=name;  
  14.     }  
  15.     //复写run方法  
  16.     public void run()  
  17.     {  
  18.         for(int x=0;x<60;x++)  
  19.         System.out.println(Thread.currentThread().getName()+"..run..."+x);  
  20. //      System.out.println(this.getName()+"..run..."+x);  
  21.     }  
  22. }  
  23.   
  24. class  ThreadTest  
  25. {  
  26.     public static void main(String[] args)   
  27.     {  
  28.         new Test("one+++").start();//开启一个线程  
  29.   
  30.         new Test("tow———").start();//开启第二线程  
  31.   
  32.         //主线程执行的代码  
  33.         for(int x=0;x<170;x++)  
  34.         System.out.println("Hello World!");  
  35.     }  
  36. }  

结果:

      如图,执行是随机、交替执行的,每一次运行的结果都会不同。

       

2、 实现方式

        使用继承方式有一个弊端,那就是如果该类本来就继承了其他父类,那么就无法通过Thread类来创建线程了。这样就有了第二种创建线程的方式:实现Runnable接口,并复习其中run方法的方式。

创建步骤:

        a,定义类实现Runnable的接口。

        b,覆盖Runnable接口中的run方法。目的也是为了将线程要运行的代码存放在该run方法中。

        c,通过Thread类创建线程对象。

        d,将Runnable接口的子类对象作为实参传递给Thread类的构造方法。

       为什么要将Runnable接口的子类对象传递给Thread的构造函数?

        因为,自定义的run方法所属的对象是Runnable接口的子类对象。所以要让线程去指定对象的run方法,就必须明确该run方法所属对象。

        e,调用Thread类中start方法启动线程。start方法会自动调用Runnable接口子类的run方法。

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

程序示例:

[java] view plaincopy
  1. /* 
  2. 需求:简单的卖票程序。 
  3. 多个窗口卖票。 
  4. */  
  5. class Ticket implements Runnable//extends Thread  
  6. {  
  7.     private  int tick = 100;  
  8.     public void run()  
  9.     {  
  10.         while(true)  
  11.         {  
  12.             if(tick>0)  
  13.             {  
  14.                 //显示线程名及余票数  
  15.                 System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);  
  16.             }  
  17.         }  
  18.     }  
  19. }  
  20.   
  21.   
  22. class  TicketDemo  
  23. {  
  24.     public static void main(String[] args)   
  25.     {  
  26.         //创建Runnable接口子类的实例对象  
  27.         Ticket t = new Ticket();  
  28.   
  29.         //有多个窗口在同时卖票,这里用四个线程表示  
  30.         Thread t1 = new Thread(t);//创建了一个线程  
  31.         Thread t2 = new Thread(t);  
  32.         Thread t3 = new Thread(t);  
  33.         Thread t4 = new Thread(t);  
  34.   
  35.         t1.start();//启动线程  
  36.         t2.start();  
  37.         t3.start();  
  38.         t4.start();  
  39.     }  
  40. }  

 

三、两种方式的区别和线程的几种状态

1、两种创建方式的区别

        继承Thread:线程代码存放在Thread子类run方法中。

        实现Runnable:线程代码存放在接口子类run方法中。      

2、几种状态

        被创建:等待启动,调用start启动。

         运行状态:具有执行资格和执行权。

         临时状态(阻塞):有执行资格,但是没有执行权。

         冻结状态:遇到sleeptime)方法和wait()方法时,失去执行资格和执行权,sleep方法时间到或者调用notify()方法时,获得执行资格,变为临时状态。

         消忙状态:stop()方法,或者run方法结束。

注:当已经从创建状态到了运行状态,再次调用start()方法时,就失去意义了,java运行时会提示线程状态异常。

图解:

   

四、线程安全问题

1、导致安全问题的出现的原因:

        当多条语句在操作同一线程共享数据时,一个线程对多条语句只执行了一部分,还没用执行完,另一个线程参与进来执行。导致共享数据的错误。

简单的说就两点:

        a、多个线程访问出现延迟。

        b、线程随机性    

注:线程安全问题在理想状态下,不容易出现,但一旦出现对软件的影响是非常大的。

2、解决办法——同步

        对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。

        在java中对于多线程的安全问题提供了专业的解决方式——synchronized(同步)

        这里也有两种解决方式,一种是同步代码块,还有就是同步函数。都是利用关键字synchronized来实现。

         a、同步代码块

        用法:

                  synchronized(对象)

                  {需要被同步的代码}

        同步可以解决安全问题的根本原因就在那个对象上。其中对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。

示例:

[java] view plaincopy
  1. /*   
  2. 给卖票程序示例加上同步代码块。 
  3. */  
  4. class Ticket implements Runnable  
  5. {  
  6.     private int tick=100;  
  7.     Object obj = new Object();  
  8.     public void run()  
  9.     {  
  10.         while(true)  
  11.         {  
  12.             //给程序加同步,即锁  
  13.             synchronized(obj)  
  14.             {  
  15.                 if(tick>0)  
  16.                 {  
  17.                     try  
  18.                     {     
  19.                         //使用线程中的sleep方法,模拟线程出现的安全问题  
  20.                         //因为sleep方法有异常声明,所以这里要对其进行处理  
  21.                         Thread.sleep(10);  
  22.                     }  
  23.                     catch (Exception e)  
  24.                     {  
  25.                     }  
  26.                     //显示线程名及余票数  
  27.                     System.out.println(Thread.currentThread().getName()+"..tick="+tick--);  
  28.                 }  
  29.             }     
  30.         }  
  31.     }  
  32. }  

        b,同步函数

        格式:

                在函数上加上synchronized修饰符即可。

        那么同步函数用的是哪一个锁呢?

        函数需要被对象调用。那么函数都有一个所属对象引用。就是this。所以同步函数使用的锁是this

拿同步代码块的示例:

[java] view plaincopy
  1. class Ticket implements Runnable  
  2. {  
  3.     private int tick=100;  
  4.     Object obj = new Object();  
  5.     public void run()  
  6.     {  
  7.         while(true)  
  8.         {  
  9.             show();  
  10.         }  
  11.     }  
  12.   //直接在函数上用synchronized修饰即可实现同步  
  13. public synchronized void show()  
  14. {  
  15.         if(tick>0)  
  16.         {  
  17.         try  
  18.         {     
  19.             //使用线程中的sleep方法,模拟线程出现的安全问题  
  20.             //因为sleep方法有异常声明,所以这里要对其进行处理  
  21.             Thread.sleep(10);  
  22.         }  
  23.         catch (Exception e)  
  24.         {  
  25.         }  
  26.         //显示线程名及余票数  
  27.         System.out.println(Thread.currentThread().getName()+"..tick="+tick--);  
  28.     }  
  29. }     
  30. }  

3、同步的前提

        a,必须要有两个或者两个以上的线程。

        b,必须是多个线程使用同一个锁。

4、同步的利弊

        好处:解决了多线程的安全问题。

        弊端:多个线程需要判断锁,较为消耗资源。

5、如何寻找多线程中的安全问题

        a,明确哪些代码是多线程运行代码。

        b,明确共享数据。

        c,明确多线程运行代码中哪些语句是操作共享数据的。

 

五、静态函数的同步方式

        如果同步函数被静态修饰后,使用的锁是什么呢?

        通过验证,发现不在是this。因为静态方法中也不可以定义this。静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。如:

        类名.class 该对象的类型是Class

这就是静态函数所使用的锁。而静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class

经典示例:

[java] view plaincopy
  1. /* 
  2. 加同步的单例设计模式————懒汉式 
  3. */  
  4. class Single  
  5. {  
  6.     private static Single s = null;  
  7.     private Single(){}  
  8.     public static void getInstance()  
  9.     {  
  10.         if(s==null)  
  11.         {  
  12.             synchronized(Single.class)  
  13.             {  
  14.                 if(s==null)  
  15.                     s = new Single();  
  16.             }  
  17.         }  
  18.         return s;  
  19.     }  
  20. }  

 

六、死锁

        当同步中嵌套同步时,就有可能出现死锁现象。

示例:

[java] view plaincopy
  1. /* 
  2. 写一个死锁程序 
  3. */  
  4.   
  5. //定义一个类来实现Runnable,并复写run方法  
  6. class LockTest implements Runnable  
  7. {  
  8.     private boolean flag;  
  9.     LockTest(boolean flag)  
  10.     {  
  11.         this.flag=flag;  
  12.     }  
  13.     public void run()  
  14.     {  
  15.         if(flag)  
  16.         {  
  17.             while(true)  
  18.             {  
  19.                 synchronized(LockClass.locka)//a锁  
  20.                 {  
  21.                     System.out.println(Thread.currentThread().getName()+"------if_locka");  
  22.   
  23.                     synchronized(LockClass.lockb)//b锁  
  24.                     {  
  25.                     System.out.println(Thread.currentThread().getName()+"------if_lockb");  
  26.                     }  
  27.                 }  
  28.             }  
  29.         }  
  30.         else  
  31.         {  
  32.             while(true)  
  33.             {  
  34.                 synchronized(LockClass.lockb)//b锁  
  35.                 {  
  36.                   System.out.println(Thread.currentThread().getName()+"------else_lockb");  
  37.   
  38.                     synchronized(LockClass.locka)//a锁  
  39.                     {  
  40.                    System.out.println(Thread.currentThread().getName()+"------else_locka");  
  41.                     }  
  42.                 }  
  43.             }  
  44.         }  
  45.     }  
  46. }  
  47.   
  48. //定义两个锁  
  49. class LockClass  
  50. {  
  51.     static Object locka = new Object();  
  52.     static Object lockb = new Object();  
  53. }  
  54.   
  55. class DeadLock  
  56. {  
  57.     public static void main(String[] args)  
  58.     {  
  59.         //创建2个进程,并启动  
  60.         new Thread(new LockTest(true)).start();  
  61.         new Thread(new LockTest(false)).start();  
  62.     }  
  63. }  

结果:程序卡住,不能继续执行

       

 

七、线程间通信

        其实就是多个线程在操作同一个资源,但是操作的动作不同。

1、使用同步操作同一资源的示例:

[java] view plaincopy
  1. /* 
  2.     有一个资源 
  3. 一个线程往里存东西,如果里边没有的话 
  4. 一个线程往里取东西,如果里面有得话 
  5. */  
  6.   
  7. //资源  
  8. class Resource  
  9. {  
  10.     private String name;  
  11.     private String sex;  
  12.     private boolean flag=false;  
  13.       
  14.     public synchronized void setInput(String name,String sex)  
  15.     {  
  16.         if(flag)  
  17.         {  
  18.             try{wait();}catch(Exception e){}//如果有资源时,等待资源取出  
  19.         }  
  20.         this.name=name;  
  21.         this.sex=sex;  
  22.   
  23.         flag=true;//表示有资源  
  24.         notify();//唤醒等待  
  25.     }  
  26.   
  27.     public synchronized void getOutput()  
  28.     {         
  29.         if(!flag)  
  30.         {  
  31.             try{wait();}catch(Exception e){}//如果木有资源,等待存入资源  
  32.         }  
  33.         System.out.println("name="+name+"---sex="+sex);//这里用打印表示取出  
  34.                   
  35.         flag=false;//资源已取出  
  36.         notify();//唤醒等待  
  37.     }  
  38. }  
  39.   
  40.   
  41. //存线程  
  42. class Input implements Runnable  
  43. {  
  44.     private Resource r;  
  45.     Input(Resource r)  
  46.     {  
  47.         this.r=r;  
  48.     }  
  49.     public void run()//复写run方法  
  50.     {  
  51.         int x=0;  
  52.         while(true)  
  53.         {  
  54.             if(x==0)//交替打印张三和王羲之  
  55.             {  
  56.                 r.setInput("张三",".....man");  
  57.             }  
  58.             else  
  59.             {  
  60.                 r.setInput("王羲之","..woman");  
  61.             }  
  62.             x=(x+1)%2;//控制交替打印  
  63.         }  
  64.     }  
  65. }  
  66.   
  67. //取线程  
  68. class Output implements Runnable  
  69. {  
  70.     private Resource r;  
  71.     Output(Resource r)  
  72.     {  
  73.         this.r=r;  
  74.     }  
  75.     public void run()//复写run方法  
  76.     {  
  77.         while(true)  
  78.         {  
  79.             r.getOutput();  
  80.         }  
  81.     }  
  82. }  
  83.   
  84.   
  85.   
  86. class ResourceDemo2   
  87. {  
  88.     public static void main(String[] args)   
  89.     {  
  90.         Resource r = new Resource();//表示操作的是同一个资源  
  91.   
  92.         new Thread(new Input(r)).start();//开启存线程  
  93.   
  94.         new Thread(new Output(r)).start();//开启取线程  
  95.     }  
  96. }  

结果:部分截图

 几个小问题:

        1)wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中?

                a,这些方法存在与同步中。

                b,使用这些方法时必须要标识所属的同步的锁。同一个锁上wait的线程,只可以被同一个锁上的notify唤醒。

                c,锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。

        2)wait(),sleep()有什么区别?

              wait():释放cpu执行权,释放锁。

              sleep():释放cpu执行权,不释放锁。

        3)为甚么要定义notifyAll

        因为在需要唤醒对方线程时。如果只用notify,容易出现只唤醒本方线程的情况。导致程序中的所以线程都等待。

2JDK1.5中提供了多线程升级解决方案。

        将同步synchronized替换成显示的Lock操作。将ObjectwaitnotifynotifyAll,替换成了Condition对象。该Condition对象可以通过Lock锁进行获取,并支持多个相关的Condition对象。

升级解决方案的示例:

[java] view plaincopy
  1. /* 
  2. 生产者生产商品,供消费者使用 
  3. 有两个或者多个生产者,生产一次就等待消费一次 
  4. 有两个或者多个消费者,等待生产者生产一次就消费掉 
  5.  
  6. */  
  7.   
  8. import java.util.concurrent.locks.*;  
  9.   
  10. class Resource   
  11. {     
  12.     private String name;  
  13.     private int count=1;  
  14.     private boolean flag = false;  
  15.       
  16.     //多态  
  17.     private Lock lock=new ReentrantLock();  
  18.   
  19.     //创建两Condition对象,分别来控制等待或唤醒本方和对方线程  
  20.     Condition condition_pro=lock.newCondition();  
  21.     Condition condition_con=lock.newCondition();  
  22.   
  23.     //p1、p2共享此方法  
  24.     public void setProducer(String name)throws InterruptedException  
  25.     {  
  26.         lock.lock();//锁  
  27.         try  
  28.         {  
  29.             while(flag)//重复判断标识,确认是否生产  
  30.                 condition_pro.await();//本方等待  
  31.   
  32.             this.name=name+"......"+count++;//生产  
  33.             System.out.println(Thread.currentThread().getName()+"...生产..."+this.name);//打印生产  
  34.             flag=true;//控制生产\消费标识  
  35.             condition_con.signal();//唤醒对方  
  36.         }  
  37.         finally  
  38.         {  
  39.             lock.unlock();//解锁,这个动作一定执行  
  40.         }  
  41.           
  42.     }  
  43.   
  44.     //c1、c2共享此方法  
  45.     public void getConsumer()throws InterruptedException  
  46.     {  
  47.         lock.lock();  
  48.         try  
  49.         {  
  50.             while(!flag)//重复判断标识,确认是否可以消费  
  51.                 condition_con.await();  
  52.   
  53.             System.out.println(Thread.currentThread().getName()+".消费."+this.name);//打印消费  
  54.             flag=false;//控制生产\消费标识  
  55.             condition_pro.signal();  
  56.         }  
  57.         finally  
  58.         {  
  59.             lock.unlock();  
  60.         }  
  61.   
  62.     }  
  63. }  
  64.   
  65. //生产者线程  
  66. class Producer implements Runnable   
  67. {  
  68.     private Resource res;  
  69.     Producer(Resource res)  
  70.     {  
  71.         this.res=res;  
  72.     }  
  73.     //复写run方法  
  74.     public void run()  
  75.     {  
  76.         while(true)  
  77.         {  
  78.             try  
  79.             {  
  80.                 res.setProducer("商品");  
  81.             }  
  82.             catch (InterruptedException e)  
  83.             {  
  84.             }  
  85.         }  
  86.     }  
  87. }  
  88.   
  89. //消费者线程  
  90. class Consumer implements Runnable  
  91. {  
  92.     private Resource res;  
  93.     Consumer(Resource res)  
  94.     {  
  95.         this.res=res;  
  96.     }  
  97.     //复写run  
  98.     public void run()  
  99.     {  
  100.         while(true)  
  101.         {  
  102.             try  
  103.             {  
  104.                 res.getConsumer();  
  105.             }  
  106.             catch (InterruptedException e)  
  107.             {  
  108.             }  
  109.         }  
  110.     }  
  111.   
  112. }  
  113.   
  114. class  ProducerConsumer  
  115. {  
  116.     public static void main(String[] args)   
  117.     {  
  118.         Resource res=new Resource();  
  119.   
  120.         new Thread(new Producer(res)).start();//第一个生产线程 p1  
  121.         new Thread(new Consumer(res)).start();//第一个消费线程 c1  
  122.   
  123.         new Thread(new Producer(res)).start();//第二个生产线程 p2  
  124.         new Thread(new Consumer(res)).start();//第二个消费线程 c2  
  125.     }  
  126. }  

运行结果:部分截图

       

 

八、停止线程

        JDK 1.5版本之前,有stop停止线程的方法,但升级之后,此方法已经过时。

那么现在我们该如果停止线程呢?

        只有一种办法,那就是让run方法结束。

1、开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。

      如:run方法中有如下代码,设置一个flag标记。  

[java] view plaincopy
  1. public  void run()  
  2. {  
  3.     while(flag)  
  4.     {     
  5.         System.out.println(Thread.currentThread().getName()+"....run");  
  6.     }  
  7. }  

        那么只要在主函数或者其他线程中,在该线程执行一段时间后,将标记flag赋值false,该run方法就会结束,线程也就停止了。

2、上面的1方法可以解决一般情况,但是有一种特殊情况:就是当线程处于冻结状态。就不会读取到标记。那么线程就不会结束。

        当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。Thread类提供该方法interrupt();

如:

[java] view plaincopy
  1. class StopThread implements Runnable  
  2. {  
  3.     private boolean flag =true;  
  4.     public  void run()  
  5.     {  
  6.         while(flag)  
  7.         {  
  8.             System.out.println(Thread.currentThread().getName()+"....run");  
  9.         }  
  10.     }  
  11.     public void changeFlag()  
  12.     {  
  13.         flag = false;  
  14.     }  
  15. }  
  16.   
  17. class  StopThreadDemo  
  18. {  
  19.     public static void main(String[] args)   
  20.     {  
  21.         StopThread st = new StopThread();  
  22.         Thread t1 = new Thread(st);  
  23.         Thread t2 = new Thread(st);   
  24.         t1.start();  
  25.         t2.start();   
  26.   
  27.         int num = 0;  
  28.         while(true)  
  29.         {  
  30.             if(num++ == 60)  
  31.             {  
  32.                 t1.interrupt();//清除冻结状态  
  33.                 t2.interrupt();  
  34.                 st.changeFlag();//改变循环标记  
  35.                 break;  
  36.             }  
  37.             System.out.println(Thread.currentThread().getName()+"......."+num);  
  38.         }  
  39.         System.out.println("over");  
  40.     }  
  41. }  

结果:

       

 

九、什么时候写多线程?

        当某些代码需要同时被执行时,就用单独的线程进行封装。

示例:

[java] view plaincopy
  1. class  ThreadTest  
  2. {  
  3.     public static void main(String[] args)   
  4.     {  
  5.         //一条线程  
  6.         new Thread()  
  7.         {  
  8.             public void run()  
  9.             {  
  10.                 for (int x=0;x<100 ;x++ )  
  11.                 {  
  12.                     System.out.println(Thread.currentThread().toString()+"....."+x);  
  13.                 }  
  14.             }  
  15.         }.start();  
  16.       
  17.         //又是一条线程  
  18.         Runnable r= new Runnable()  
  19.         {  
  20.             public void run()  
  21.             {  
  22.                 for (int x=0;x<100 ;x++ )  
  23.                 {  
  24.                     System.out.println(Thread.currentThread().getName()+"....."+x);  
  25.                 }  
  26.             }  
  27.         };  
  28.         new Thread(r).start();  
  29.           
  30.         //可以看作主线程  
  31.         for (int x=0;x<1000 ;x++ )  
  32.         {  
  33.             System.out.println("Hello World!");  
  34.         }  
  35.           
  36.     }  
  37. }  

 

扩展小知识:

1join方法

        当A线程执行到了b线程的.join()方法时,A线程就会等待,等B线程都执行完,A线程才会执行。(此时B和其他线程交替运行。)join可以用来临时加入线程执行。

2setPriority()方法用来设置优先级

        MAX_PRIORITY 最高优先级10

        MIN_PRIORITY   最低优先级1

        NORM_PRIORITY 分配给线程的默认优先级

3yield()方法可以暂停当前线程,让其他线程执行。

 

-----------android培训java培训、java学习型技术博客、期待与您交流!------------

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机百度上下载的文档打不开怎么办 5岁宝宝乘飞机没带证件怎么办 网上订飞机票忘记订儿童票了怎么办 两岁宝宝对牛奶鸡蛋过敏了怎么办 两岁宝宝坐不住好跑怎么办 宝宝两岁多了不愿意坐小马桶怎么办 坐火车小孩拉屎在被子上怎么办 川航飞机票名字错了一个字怎么办 胜战本领怎么看走向战场怎么办 数数字油画你的颜料干了怎么办? 数字油画涂颜料涂错了怎么办 绝地求生模拟器注册已达上限怎么办 孕妇把番茄和虾一起吃了怎么办 4岁宝贝吃了玩具小电池怎么办 微信使用零钱需完善实名信息怎么办 两岁宝宝刷牙不会吐水怎么办 孩子牙龈上长了小牙怎么办 供暖公司未供暖却收取供暖费怎么办 两岁宝宝认知和语言能力低怎么办 蜡笔同步被对方发现删掉的怎么办 微信时间和手机时间不同步怎么办 孩子们家乡爱画美丽的也自己怎么办 娃把豆豆弄进鼻孔了怎么办 20岁了不知道自己该干什么怎么办 遇到一个新手买家恶意拍下怎么办 淘宝卖螃蟹有什么要求美工怎么办 淘宝衣服吊牌剪了想退货怎么办修 用图片在淘宝搜衣服搜不到怎么办 汽车黑塑料水砂纸磨的不平怎么办 sat报名要你填10位电话怎么办 手绘板连接电脑绘画有点迟钝怎么办 走路不小心滑了一下特尴尬怎么办 小孩子头撞了头发长不出来怎么办 小孩子头磕破了不长头发怎么办 晚上洗了冷水头早上头痛怎么办 头发洗了一天就油了怎么办 米诺地尔搽剂喷了头皮油怎么办 头发可以种植吗如果是秃顶怎么办 前额头发少怎么办如何使头发增多 头发又细又软又少怎么办 宝宝一岁了头发又少又黄怎么办