JAVA多线程

概述

线程是进程中的内容,而每一个应用程序里面至少有一个线程。

1.什么是线程?

线程:是进程中用于控制程序执行的控制单元(执行路径,执行情景)

 

2.什么是进程?

进程:是正在执行中的程序,每一个进程在执行时都有一个执行顺序,该顺序是一个执行路径,或叫做一个控制单元。

 

示例:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void main(String[] args){  
  2.     for(int x = 1; x<4000;x++)  
  3.         System.out.println(“Hello Word!”);}  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

在我们启动JVM执行这个程序时,会有一个叫java.exe的进程。

因为进程中至少有一个线程,所以说明该进程中至少有一个线程在负责java程序的执行。

而这个线程运行的代码存放在main方法中,所以该线程也称为主线程。

3.多线程存在的意义

多线程的出现可以让我们程序中的部分能产生同时运行的效果。

例如:

其实如果更细节的说明,在JVM启动时是不止一个线程的,还有负责垃圾回收机制的线程。

如果JVM只有一个线程,没有垃圾回收线程,会有什么后果呢?

主线程在一直运行,在执行过程中堆内存中会存放很多很多垃圾,在主线程执行完后在做垃圾回收动作。可是,如果主线程在执行过程中垃圾太多堆内存放不下了,主线程就会先停下把垃圾先回收,解决之后在往下继续执行,而它在解决垃圾时我们的程序就会停止,这就很不合理。

如果JVM有多个线程,主线程在运行程序,还有一个线程在负责垃圾回收,这样程序就会更优化。

4.如何在程序中自定义线程?

Java给我们提供了对像线程这类事物的描述,该类是Thread类。

该类中定义了,创建线程对象的方法(构造函数),提供了要被线程执行的代码存储的位置(run()方法),还定义了开启线程运行的方法(start())

Java还给我们提供了一个规则,实现Runnable接口。如果自定义类不继承Thread,也可以实现Runnable接口。并将多线程要运行的代码存放在Runnablerun方法中。

创建线程

方式一:继承Thread类

   步骤:

           1.定义一个类,继承Thread

           2.复写Thread类中的run方法,方法中写需要在新线程中执行的代码

           3.创建Thread类的子类对象,调用线程的start方法

   代码实现:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.          public class Demo extends Thread{  
  2. public void run(){//复写Thread类中的run方法  
  3.     //这里用来存放我们要线程执行的代码  
  4.     System.out.println(“我的线程1”);  
  5.                 }  
  6.          }  
  7.  public class DemoTest{  
  8. public static void main(String[] args){  
  9. Demo d = new Demo();//创建一个线程  
  10. d.start();//开启线程并执行该线程的run方法  
  11. //d.run();//仅仅是对象调用方法,而线程创建了并没有运行  
  12.                    //也可以用匿名的方式  
  13.                    //new Demo().start();  
  14.                 }  
  15.          }  

1).为什么要覆盖run方法呢?

      我们为什么要开启线程,就是为了要让线程去执行我们定义的某些代码,让这些代码起      到同时运行的效果。

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

      所以我们覆盖父类中run方法,在run方法中存放我们要执行的代码。

2).start方法的作用

      该方法有两个作用:启动线程,调用并执行run方法。

     注意:如直接调用run()方法,则是主线程执行其中代码,不会开启新线程。

 

方式二:实现Runnable

   步骤:

           1. 定义类实现Runnable接口

           2.覆盖Runnable接口中的run方法,将多线程要运行的代码存入其中。

           3.通过Thread类建立线程对象,并将Runnable接口的子类对象作为参数传递给Thread的构造函数。

           4.调用Thread对象的start方法开启线程。

   代码实现:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class Demo implements Runnable{  
  2.     public void run(){  
  3.     //将线程要运行的代码存放在该run方法中  
  4.         System.out.println(“我的线程2”);  
  5.     }  
  6. }  
  7. public class DemoTest{  
  8.     public static void main(String[] args){  
  9.     Demo d = new Demo();//这里不是创建线程  
  10.     Thread t = new Thread(d);//这里是创建线程  
  11.     t.start();//启动线程  
  12.     //匿名的方式  
  13.     //new Thread(new Demo()).start();  
  14.     }  
  15. }  

  注意:实现Runnable时这个类还不是线程,创建线程的是Thread类对象或Thread子类对象。

 1).为什么要设计Runnable接口?

      假设我们有两个类AB,它们有一些共性代码,我们通过向上的不断抽取,出现了一个父类。可是A类中有一部分代码是需要被多线程所执行,因为java支持的是单继承,它已经继承了一个类了,所以不能在继承Thread类。java支持多实现所以就设计了Runnable接口。

 2).Runnable接口应该由哪些类来实现?

     Runnable接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个名称为run的无参数方法。

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

     因为线程要运行的代码都在Runnable子类的run方法中存储。所以要将该run方法所属的对象传递给Thread。让Thread线程去使用该对象调用其run方法。

 4).继承Thread类和实现Runnable接口建立线程有什么区别?

  1.它们线程代码存放位置不同

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

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

  2.局限性

    实现Runnable接口避免了单继承的局限性。而且实现Runnable接口这个对象中的数据共享(如果不用静态修饰共享数据是在堆内存中)

 

  注意:在定义线程时,建议使用实现Runnable接口方式。

线程运行状态


 

 

 

 

 

临时状态:有执行资格,没有执行权。

冻结状态:没有执行资格的情况下。

运行状态:有执行资格,有执行权。

sleep方法与wait方法的区别?

sleep():不会释放对象锁,有执行权,时间结束后,自动恢复线程。

wait():释放对象锁,进入等待此对象线程池中,只有针对此对象发出notify方法或notifyAll方法后此线程才进入临时状态准备获得执行权进入运行状态。

注意:其中的stop方法现在已经过时用不了,他被新方法interrupt方法所代替。冻结状态的线程都会在线程池中。

同步

我们在运行多线程代码时发现运行结果每一次都不同,说明多线程具备随机性,因为这是由CPU不断的快速切换造成的。这就有可能会产生问题。

问题产生的原因:

     1,多线程代码中有操作共享数据。

     2,多条语句操作该共享数据。

当具备这两点时:有一个线程对多条操作共享数据的代码只执行了一部分时,另一个线程就开始参与执行,这就会发生数据错误。

解决方法:当一个线程在执行多条操作共享数据代码时,其它线程即使获取了执行权,也不可以参与操作。

Java对这种解决方式提供了专业的代码——同步。

同步的原理:就是将部分操作功能数据的代码进行加锁(也叫监视器)

同步的前提:

     1.必须要有两个或两个以上的线程。

     2.必须是多个线程使用同一个锁。

同步的好处与弊端:

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

       弊端:较为消耗资源,同步嵌套后容易死锁。

什么是死锁?

代码示例:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class Test implements Runnable  
  2. {  
  3.         private boolean flag;//定义一个布尔型变量  
  4.         Test(boolean flag)  
  5.         {  
  6.             this.flag = flag;  
  7.         }  
  8.       
  9.         public void run(){  
  10.             if(flag){  
  11.                 //同步代码块的嵌套  
  12.                 synchronized(DuiXiang.t1){//锁1  
  13.                     System.out.println("if ----1");  
  14.               
  15.                     synchronized (DuiXiang.t2){//锁2  
  16.                         System.out.println("if----2");  
  17.                     }     
  18.                 }     
  19.       
  20.             }  
  21.             else{  
  22.                 synchronized(DuiXiang.t2){//锁2  
  23.                     System.out.println("else----2");  
  24.                     synchronized (DuiXiang.t1){//锁1  
  25.                         System.out.println("else----1");  
  26.                     }     
  27.                 }  
  28.             }  
  29.         }  
  30. }  
  31.   
  32. class DuiXiang{//为了方便测试,所以把对象单独提取出来  
  33.        static Object t1 = new Object();//定义一个静态的Object对象  
  34.        static Object t2 = new Object();  
  35. }  
  36.   
  37. class TestDemo{  
  38.     public static void main(String[] args){  
  39.         Thread h1 = new Tread(new Tesst(true));//创建线程  
  40.         Thread h2 = new Tread(new Tesst(false));  
  41.         h1.start();//启动线程  
  42.         h2.start();  
  43.     }  
  44. }  

 

注意:我们在开发时一定要注意避免死锁。

同步的表现形式:

     1.      同步代码块

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. synchronized(对象){  
  2.     需要被同步的代码  
  3. }  

    2.       同步函数

           1.一般同步函数

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public synchronized void 方法名(){  
  2.     需要被同步的代码  
  3. }   

           2).静态同步函数

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public synchronized static void 方法名(){//静态同步函数  
  2.     需要被同步的代码  
  3. }   

同步代码快与同步函数有什么不同?

     它们的锁不同:

          同步代码块:锁是任意对象。

          同步函数:一般同步函数是this。静态同步函数是类名.class,是该类的字节码文件对象(涉及示例:单例设计模式的懒汉式)

如何找安全问题?

        1.明确哪些代码是多线程运行代码。

        2.明确共享数据。

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

注意:一定要明白哪里可以用同步哪里不可以用,也不可以把run方法都放到同步里,那样就相当成了单线程。

多线程的一些方法

       currentThread():获取当前正在执行的线程对象

       getName():获取线程名称

       Thread.currentThread().getName():线程名称

       设置线程名称:

              1.      setName();

              2.    构造函数

                       类名(String name){

                               super(name);//父类有这个构造函数,所以直接调用就行

                       }

设置线程名称的意义

我们想要知道当前到底是哪一个线程在运行,我们可以获取其名称并进行判断。 

wait():等待。//这里会发生异常

notify():唤醒一个。

notifyAll():唤醒线程池中的所有。

上面这三个都使用在同步中,因为要对持有监视器()的线程操作。所以要使用在同步中,因为只有同步才具有锁。

为什么这三个操作线程的方法要定义Object类中呢?

 因为这些方法在操作同步中线程时,都必须要标识它们所操作线程持有的锁。

只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。

不可以对不同锁中的线程进行唤醒。

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

       ThreadGroup():线程组。一般情况下,是谁开启这个线程的,这个线程就属于哪个组。

       toString():返回该线程的字符串表示形式,包括线程名称、优先级和线程组。一般用的不多。

多线程示例

线程间通信:就是多个线程在操作同一个资源,但操作的动作不同,如:我们有一些数据,a在往里存,b在往出取。

等待唤醒机制示例:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class XianCheng {  
  2.     public static void main(String[] args) {  
  3.         Res r = new Res();  
  4.         new Thread(new Input(r)).start();//创建线程并启动  
  5.         new Thread(new Output(r)).start();  
  6.     }  
  7. }  
  8.   
  9. class Res{  
  10.     private String name;//姓名  
  11.     private String sex;//性别  
  12.     private boolean fal;//默认是false  
  13.     public synchronized void set(String name,String sex){  
  14.         if(fal)//判断  
  15.             try {  
  16.                 this.wait();//这里会出现异常,所以只能try或抛  
  17.             } catch (InterruptedException e) {  
  18.                 e.printStackTrace();  
  19.             }  
  20.         this.name = name;  
  21.         this.sex = sex;  
  22.         fal = true;  
  23.         this.notify();//唤醒一个线程  
  24.     }  
  25.       
  26.     public synchronized void out(){  
  27.         if(!fal)//这里是不等于ture,因为上面给付了true  
  28.             try {  
  29.                 this.wait();  
  30.             } catch (InterruptedException e) {  
  31.                 e.printStackTrace();  
  32.             }  
  33.         System.out.println(name+"----------"+sex);  
  34.         fal = false;  
  35.         this.notify();  
  36.     }  
  37. }  
  38.   
  39. //输入姓名 性别  
  40. class Input implements Runnable{  
  41.     private Res r;//建立Res的引用,确保拿到的是同一个对象  
  42.     Input(Res r){  
  43.         this.r = r;  
  44.     }  
  45.     public void run() {  
  46.         int x = 0;  
  47.         while(true){  
  48.         if(x==0)  
  49.             r.set("小丽""女");  
  50.         else  
  51.             r.set("Jack""man");  
  52.         x=(x+1)%2;  
  53.     }  
  54.     }  
  55. }  
  56.   
  57. //输出姓名 性别  
  58. class Output implements Runnable{  
  59.     private Res r;  
  60.     Output(Res r){  
  61.         this.r = r;  
  62.     }  
  63.     public void run() {  
  64.         while(true)  
  65.             r.out();  
  66.     }  
  67. }  


 

等待的线程放在哪里呢?

在线程运行时内存中会建立一个线程池,等待线程都存在这个线程池中,当我们notify时唤醒的都是线程池中的线程,通常唤醒第一个被等待的,因为它是按顺序往里存的。

 

停止线程与守护线程

如何停止线程

1.       定义循环结束标记,让run方法结束,因为线程运行代码一般都是循环,只要控制了循环就可以让run方法结束,也就是线程结束。

2.       使用interrupt方法,该方法是结束线程的冻结状态,使线程回到运行状态中来。

 

特殊情况:

当线程处于了冻结状态,就不会读取到标记,那么线程就不会结束。当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。强制让线程恢复到运行状态,这样就可以操作标记让线程结束。

 

守护线程

setDaemon(boolean on):将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,java虚拟机退出。该方法必须在启动线程前调用。

守护线程相当于后台线程,前台线程如果结束,后台线程自动结束。

 

守护线程代码示例:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class StopThread implements Runnable  
  2. {  
  3.     private boolean flag =true;//定义布尔型变量,赋初值true  
  4.     public void run()  
  5.     {  
  6.         while(flag)  
  7.         {  
  8.             /* 
  9.             try{ 
  10.                 wait();//等待 
  11.             } catch (InterruptedException e) { 
  12.                 // TODO Auto-generated catch block 
  13.                 e.printStackTrace(); 
  14.             } 
  15.             */  
  16.             System.out.println(Thread.currentThread().getName()+"....run");  
  17.         }  
  18.     }  
  19.     public void changeFlag()  
  20.     {  
  21.         flag = false;  
  22.     }  
  23. }  
  24.   
  25. class  StopThreadDemo  
  26. {  
  27.     public static void main(String[] args)   
  28.     {  
  29.         StopThread st = new StopThread();  
  30.           
  31.         Thread t1 = new Thread(st);//创建线程  
  32.         Thread t2 = new Thread(st);  
  33.   
  34.         t1.setDaemon(true);//定义守护线程  
  35.         //t2.setDaemon(true);  
  36.         t1.start();  
  37.         t2.start();  
  38.   
  39.         int num = 0;  
  40.         while(true)  
  41.         {  
  42.             if(num++ == 60)  
  43.             {  
  44.                 st.changeFlag();  
  45.                 //t1.interrupt();//停止线程  
  46.                 //t2.interrupt();  
  47.                 break;  
  48.             }  
  49.             System.out.println(Thread.currentThread().getName()+"......."+num);  
  50.         }  
  51.         System.out.println("over");  
  52.     }  
  53. }  


 

Join与yield方法示例:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class Demo implements Runnable  
  2. {  
  3.     public void run()  
  4.     {  
  5.         for(int x=0; x<70; x++)  
  6.         {  
  7.             //返回该线程的字符串表示形式,包括线程名称、优先级和线程组  
  8.             System.out.println(Thread.currentThread().toString()+"....."+x);  
  9.             Thread.yield();//调用yield()方法释放执行权  
  10.         }  
  11.     }  
  12. }  
  13.   
  14.   
  15. class  JoinDemo  
  16. {  
  17.     public static void main(String[] args) throws Exception  
  18.     {  
  19.         Demo d = new Demo();  
  20.         Thread t1 = new Thread(d);//创建线程  
  21.         Thread t2 = new Thread(d);  
  22.         //t1.join();//这里会有一个异常,可以try或抛  
  23.         t1.start();  
  24.           
  25.         //t1.setPriority(Thread.MAX_PRIORITY);//定义线程优先级  
  26.         t2.start();  
  27.         for(int x=0; x<80; x++)  
  28.         {  
  29.             //System.out.println("main....."+x);  
  30.         }  
  31.         System.out.println("over");  
  32.     }  
  33. }  


 

join方法:等待该线程终止。

特点:当A线程执行到了B线程的.join()方法时,A线程就会等待。等B线程都执行完,A线程才会执行。Join方法可以用来临时加入线程执行。

 

yield方法:暂停当前正在执行的线程对象,并执行其他线程。

特点:线程一读到Thread.yield();就会释放执行权,临时释放用到。可以稍微减缓一下线程的运行。

 

优先级

setPriority():更改线程的优先级。

优先级是110

默认优先级是:5

 

MAX_PRIORITY:线程可以具有的最高优先级。10

MIN_PRIORITY:线程可以具有的最低优先级。1

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

注意:凡是数据是固定的就定义成常量,凡是数据是共享的就定义成静态。

 

生产者消费者示例:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class XianCheng1 {  
  2.     public static void main(String[] args) {  
  3.         Ress r = new Ress();  
  4.         /* 
  5.         new hread(new Sheng(r)).start();//创建线程并启动线程 
  6.         new Thread(new Xiao(r)).start(); 
  7.         */  
  8. Sheng s = new Sheng(r);  
  9.         Xiao x = new Xiao(r);  
  10.   
  11.         Thread t1 = new Thread(s); //创建线程  
  12.         Thread t2 = new Thread(s);   
  13.         Thread t3 = new Thread(x);   
  14.         Thread t4 = new Thread(x);   
  15.   
  16.         t1.start();//启动线程<p align="left"><span style="color:black;"><span style="font-family:Times New Roman;">                  t2.start();</span></span></p><p align="left"><span style="color:black;"><span style="font-family:Times New Roman;">     t3.start();</span></span></p><p align="left"><span style="color:black;"><span style="font-family:Times New Roman;">     t4.start();</span></span></p> }  
  17. }  
  18.   
  19. class Ress{  
  20.     private String name;  
  21.     private int count = 1;  
  22.     private boolean fa = false;  
  23.       
  24.     public synchronized void set(String name){  
  25.         while(fa)  
  26.             try {  
  27.                 wait();//等待  
  28.             } catch (InterruptedException e) {  
  29.                 e.printStackTrace();  
  30.             }  
  31.         this.name = name+"---"+count++;//让count自增  
  32.         System.out.println(Thread.currentThread().getName()+"---生产者--"+this.name);  
  33.         fa = true;  
  34.         notifyAll();//唤醒所有  
  35.     }  
  36.       
  37.     public synchronized void out(){  
  38.         while(!fa)  
  39.             try {  
  40.                 wait();  
  41.             } catch (InterruptedException e) {  
  42.                 e.printStackTrace();  
  43.             }  
  44.         System.out.println(Thread.currentThread().getName()+"----------消费者--"+this.name);  
  45.         fa = false;  
  46.         notifyAll();  
  47.     }  
  48. }  
  49.   
  50. class Sheng implements Runnable{  
  51.     private Ress r;//定义对象引用  
  52.     Sheng(Ress r){  
  53.         this.r = r;  
  54.     }  
  55.     public void run() {  
  56.         while(true)  
  57.             r.set("==商品==");  
  58.     }  
  59. }  
  60.   
  61. class Xiao implements Runnable{  
  62.     private Ress r;  
  63.     Xiao(Ress r){  
  64.         this.r = r;  
  65.     }  
  66.     public void run() {  
  67.         while(true)  
  68.             r.out();  
  69.     }  
  70. }  

对于这个示例我们不可以定义if语句了只能定义while语句,为什么呢?

因为是多个消费者和多个生产者,需要让被唤醒的线程再一次判断标记。

为什么定义notifyAll()

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

if语句只适用在只有一个生成者和消费者的时候。

 

这个问题怎么解决呢?

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

将同步synchronized替换成显示了Lock操作。

Object中的wait,notify,notifyAll,替换成了Condition对象。

该对象可以将Lock锁进行获取。

该示例中,实现了本方只唤醒对方的操作。

新特性示例:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. import java.util.concurrent.locks.Condition;  
  2. import java.util.concurrent.locks.Lock;  
  3. import java.util.concurrent.locks.ReentrantLock;  
  4. //一定要导包,否则有错误  
  5. class XianCheng2 {  
  6.     public static void main(String[] args) {  
  7.         Ress1 r = new Ress1();  
  8.   
  9.         Sheng1 s = new Sheng1(r);  
  10.         Xiao1 x = new Xiao1(r);  
  11.   
  12.         Thread t1 = new Thread(s); //创建线程  
  13.         Thread t2 = new Thread(s);   
  14.         Thread t3 = new Thread(x);   
  15.         Thread t4 = new Thread(x);   
  16.   
  17.         t1.start();//启动线程  
  18.         t2.start();  
  19.         t3.start();  
  20.         t4.start();  
  21.   
  22.     }  
  23. }  
  24.   
  25. class Ress1 {  
  26.     private String name;  
  27.     private int count = 1;  
  28.     private boolean fa = false;  
  29.   
  30.     private Lock lock = new ReentrantLock();//创建Lock的实现类对象。  
  31.     private Condition condition_sheng = lock.newCondition();//新Condition实例。  
  32.     private Condition condition_xiao = lock.newCondition();  
  33.   
  34.     public void set(String name) throws InterruptedException {  
  35.         lock.lock();//获取锁  
  36.             try {  
  37.                 while (fa)  
  38.                     condition_sheng.await();//生产者等待  
  39.                 this.name = name + "---" + count++;  
  40.                 System.out.println(Thread.currentThread().getName()+ "---生产者--" + this.name);  
  41.                 fa = true;  
  42.                 condition_xiao.signal();//唤醒消费者  
  43.                 } finally {//一定执行语句  
  44.                     lock.unlock();//释放锁  
  45.                 }  
  46.     }  
  47.   
  48.     public void out() throws InterruptedException {  
  49.         lock.lock();  
  50.           
  51.             try {  
  52.                 while (!fa)  
  53.                     condition_xiao.await();  
  54.                 System.out.println(Thread.currentThread().getName()+ "----------消费者--" + this.name);  
  55.                 fa = false;  
  56.                 condition_sheng.signal();  
  57.             } finally {  
  58.                 lock.unlock();  
  59.             }  
  60.     }  
  61. }  
  62.   
  63. class Sheng1 implements Runnable {  
  64.     private Ress1 r;  
  65.     Sheng1(Ress1 r) {  
  66.         this.r = r;  
  67.     }  
  68.     public void run() {  
  69.         while (true)  
  70.             try {  
  71.                 r.set("==商品==");  
  72.             } catch (InterruptedException e) {  
  73.                 e.printStackTrace();  
  74.             }  
  75.     }  
  76. }  
  77.   
  78. class Xiao1 implements Runnable {  
  79.     private Ress1 r;  
  80.     Xiao1(Ress1 r) {  
  81.         this.r = r;  
  82.     }  
  83.   
  84.     public void run() {  
  85.         while (true)  
  86.             try {  
  87.                 r.out();  
  88.             } catch (InterruptedException e) {  
  89.                 e.printStackTrace();  
  90.             }  
  91.     }  
  92. }  

Lock:它是一个接口,实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操

作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的Condition对象。

ReentrantLock:是Lock的实现类。

 

Lock:替代了synchronized方法和语句的使用。

       lock ():获取锁。

       unlock():释放锁。

       newCondition():返回绑定到此Lock实例的新Condition实例。

Condition:替代了Object监视器方法的使用(wait notify notifyAll),它也是一个接口。

       await();等待,会抛异常。

       signal();唤醒一个等待线程。

       signalAll();唤醒所有等待线程。

注意:要把lock.unlock();放到finally里,释放锁的资源。

新特性好处:一个锁上可以有多个相关的Condition

总结:

       run方法是将自定义代码存储的地方,不可以直接调用。

       我们在开发时建议使用创建线程的实现Runnable接口方法,因为Java里面只允许单一继承,但允许实现多个接口。实现Runnable接口方法更加灵活。

      多线程的安全问题与多线程的随机性有关,解决方法就是同步。

      线程在我们不自定义起名时有默认的名称,Thread-编号,该编号从0开始。

      finally里一般是用来释放资源的,join就是在要主线程的CPU执行权。Join有加入的意思。

      等待和唤醒必须是同一个锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值