`

多线程(Thread)技术 及线程安全(Synchronized)技术 学习笔记

阅读更多

 

 

本文查阅方法:
    1、查阅目录 —— 查阅本文目录,确定想要查阅的目录标题
    2、快捷“查找” —— 在当前浏览器页面,按键 “Ctrl+F” 按键组合,开启浏览器的查找功能,
             在查找搜索框中 输入需要查阅的 目录标题,便可以直接到达 标题内容 的位置。
    3、学习小结 —— 文中的学习小结内容,是笔者在学习之后总结出的,开发时可直接参考其进行应用开发的内容, 进一步加快了本文的查阅 速度。(水平有限,仅供参考。)

 

 

 


 

 

 

本文目录 

 

    学习小结

 

     1、多线程 概述

 

     2、创建线程的方式一:继承Thread类。

 

     3、线程运行 的 5种状态

 

     3、多线程的随机性 

 

     4、创建线程的第二种方式:实现Runable接口

 

     5、多线程运行时的 安全问题—— synchronize同步代码块

 

     6、多线程运行时的 安全问题—— 同步函数 

 

     7、多线程运行时的 安全问题—— 静态 同步函数 

 

     8、多线程应用实例:单例设计模式——懒汉式

 

     9、多线程运行问题 ———— 死锁

 

     10、线程间通信 —— 解决安全问题:等待唤醒机制

 

     11、线程间通信——多个并发线程的生产者和消费者 (经典示例) 

 

     12、线程间通信——多个并发线程的 生产者和消费者——JDK5.0 升级版:Lock 和 Condition 

 

     13、多线程————停止线程

 

     14、守护线程 Join / 线程优先级  /  yield 方法  

 

     15、多线程在实际应用中的演示

 

    

 

 

 


 

学习小结

    (1)创建线程类

 

      实现Runnable接口,并复写其run()方法。

 

      Demo:  Thread thread=new Thread(new Runnable(){

 

                      public void run(){

 

                             synchronized(new Object()){

 

                                  需要被同步的代码。

 

                            }

 

                      }

 

                });

 

                thread.start();

 

     

 

    (2)synchronize同步代码块

 

        synchronized(new Object()){

 

          需要被同步的代码。

 

        }

 

    

 

    (3)同步函数 与 静态同步函数 

 

          public synchronized void out(){  }

 

          public static synchronized void out(){  }

 

     

 

    (4)使当前线程休眠:

 

         ​ Thread.sleep(3000)  :  3秒

 

    

 

    (5)本文对于多线程技术讲解得很浅,适用于初学者。对于需要专门开发多线程相关的Web应用,还请查阅更为全面、深刻的教程,我也会尽快整理 更深一些的学习笔记供大家参考。

 

 

 

 


 

 

 

1、多线程 概述

 

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

 

    线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。一个进程中至少有一个线程。 

 

    主线程:Java VM  启动的时候会有一个进程java.exe.该进程中至少一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。

 

    【扩展:其实更细节说明jvm启动后的线程:jvm启动不止一个线程,还有负责垃圾回收机制的线程。】

 


 

 

 

2、创建线程的方式一:继承Thread类。

 

    (1)自定义类,继承Thread类 。

 

    (2)复写Thread类中的run方法。

 

       目的:将要运行的代码 存储在run方法,让线程运行。

 

    (3)调用线程的start方法,

 

         该方法两个作用:a.启动线程; b.调用run方法。

 

   

 

 Demo样例:

 

    class Demo extends Thread

 

    {

 

         public void run(){

 

              for(int x=0; x<60; x++)

 

                   System.out.println("demo run----"+x);

 

         }

 

    }

 

     

 

    class ThreadDemo 

 

    {

 

     public static void main(String[] args) {

 

          //for(int x=0; x<4000; x++)

 

          //System.out.println("Hello World!");

 

          Demo d = new Demo();//创建好一个线程。

 

          //d.start();//开启线程并执行该线程的run方法。

 

          d.run();//仅仅是对象调用方法。而线程创建了,并没有运行。     

 

          for(int x=0; x<60; x++)

 

           System.out.println("Hello World!--"+x);

 

           }

 

    }

 

    

 

 

 


 

3、线程运行 的 5种状态

 



 

 

 

 


 

 

 

3、多线程的随机性  

 

    在运行多线程程序时发现运行结果每一次都不同。因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。cpu在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象把多线程的运行行为在互相抢夺cpu的执行权。谁抢到谁执行,至于执行多长,cpu说的算。

 

   【明确一点:在某一个时刻,只能有一个程序(线程)在运行。(多核除外)】

 

 

 


 

 

 

4、创建线程的第二种方式:实现Runable接口

 

    创建步骤:(1)自定义类实现Runnable接口

 

              (2)覆盖Runnable接口中的run方法: 将线程要运行的代码存放在该run方法中。

 

              (3)通过Thread类建立线程对象。

 

              (4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。 

 

              (5)调用Thread类的start()方法开启线程并调用Runnable接口子类的run方法。  

 

    【备注:将Runnable接口的子类对象传递给Thread的构造函数,是因为自定义的run方法所属的对象是Runnable接口的子类对象。 所以要让线程去执行指定对象的run方法,就必须明确该run方法所属对象。】 

 

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

 

    实现方式和继承方式的区别:

 

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

 

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

 

   

 

  Demo样例:

 

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

 

        class Ticket implements Runnable   //extends Thread

 

        {

 

             private  int tick = 100;

 

             public void run(){

 

                  while(true){

 

                       if(tick>0){

 

                            System.out.println(Thread.currentThread().getName()+ tick--);

 

                       }

 

                  }

 

             }

 

        }

 

 

 

        class  TicketDemo

 

        {

 

             public static void main(String[] args){

 

                //下面是实现Runnable接口的方式

 

                  Ticket ticket  = new Ticket();

 

                  Thread thread1 = new Thread(ticket ,"窗口1    ");//创建了一个线程;

 

                  Thread thread2 = new Thread(ticket ,"窗口2    ");//创建了一个线程;

 

                  Thread thread3 = new Thread(ticket ,"窗口3    ");//创建了一个线程;

 

                  Thread thread4 = new Thread(ticket ,"窗口4    ");//创建了一个线程;

 

                  thread1.start();

 

                  thread2.start();

 

                  thread3.start();

 

                  thread4.start();       

 

      

 

                  /*   这是继承Thread类的方式。

 

                    Ticket ticket1 = new Ticket();

 

                    Ticket ticket2 = new Ticket();

 

                    Ticket ticket3 = new Ticket();

 

                    Ticket ticket4 = new Ticket();

 

                    ticket1.start();

 

                    ticket2.start();

 

                    ticket3.start();

 

                    ticket4.start();

 

                  */

 

             }

 

        }

 

 

 


 

  

 

5、多线程 运行时的 安全问题—— synchronize同步代码块

 

    (1)多线程运行安全问题的由来

 

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

 

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

 

    (2)Java对于多线程运行时的安全问题提供了专业的解决方式。

 

        采用Snchronize 同步代码块的方式来解决:

 

        语法:synchronized(对象)

 

            {

 

                 需要被同步的代码

 

            }

 

        同步原理:括号中的“对象”如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。现实中的例子:火车上的卫生间---经典。

 

    (3)同步的前提:

 

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

 

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

 

        【备注:必须保证同步中只能有一个线程在运行。】

 

    (4)使用Snchronize 同步代码块 的利弊

 

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

 

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

 

Demo样例:

 

class Ticket implements Runnable

 

{

 

     private  int tick = 1000;

 

     Object obj = new Object();

 

     public void run(){

 

          while(true){

 

               synchronized(obj){

 

                    if(tick>0){

 

                         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);

 

          t1.start();

 

          t2.start();

 

          t3.start();

 

          t4.start();

 

     }

 

}

 

 

 


 

6、多线程运行时的 安全问题—— 同步函数 

 

    语法:在自定义函数的返回值类型前面加 synchronized  标识即可:

 

        例:public synchronized void show(){ 

 

                 需要被同步的代码   

 

             }

 

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

 

 

 

Demo样例:

 

//需求分析:通过该程序进行验证:使用两个线程来买票,一个线程在同步代码块中,一个线程在同步函数中,都在执行买票动作。 

 

class Ticket implements Runnable

 

{

 

     private  int tick = 100;

 

     Object obj = new Object();

 

     boolean flag = true;

 

     public  void run(){

 

          if(flag){

 

               while(true){

 

                    synchronized(this){

 

                         if(tick>0){

 

                              try{

 

                                  Thread.sleep(10);

 

                               }catch(Exception e){  }

 

                               System.out.println(Thread.currentThread().getName()+"....code : "+ tick-- );

 

                         }

 

                    }

 

               }

 

          }

 

          else

 

               while(true)

 

                    show();

 

     }

 

     public synchronized void show(){ //this     //同步函数没有显性的锁,但是隐含着 锁:this 

 

          if(tick>0){

 

               try{

 

                    Thread.sleep(10);

 

                }catch(Exception e){  }

 

               System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--);

 

          }

 

     }

 

}

 

 

 

class  ThisLockDemo

 

{

 

     public static void main(String[] args) {

 

          Ticket t = new Ticket();

 

          Thread t1 = new Thread(t);

 

          Thread t2 = new Thread(t);

 

          t1.start();

 

          try{

 

              Thread.sleep(10);

 

          }catch(Exception e){  }

 

          t.flag = false;

 

          t2.start();

 

         

 

        //  Thread t3 = new Thread(t);

 

        //  Thread t4 = new Thread(t);

 

        //  t3.start();

 

        //  t4.start();

 

     }

 

}

 


 

 

 

7、多线程运行时的 安全问题—— 静态 同步函数 

 

     语法:在自定义静态函数的返回值类型前面加 synchronized  标识即可:

 

            例:public static synchronized void show(){ 

 

                     需要被同步的代码   

 

                 }

 

    锁:静态的同步函数 ,使用的锁是该方法所在类的字节码文件对象 --- “当前类名.class” 

 

    静态的同步函数的锁不在是this的原因:首先静态函数中也不可以定义this。其次静态函数进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象--类名.class ,该对象的类型是Class,所以锁对象自然就是“当前类名.class”  

 

    【备注:在静态方法内部 使用同步代码块时,其所用的锁对象也要使用静态的对象“当前类名.class”】

 

 

 

Demo样例:

 

class Ticket implements Runnable

 

{

 

     private static  int tick = 100;

 

     //Object obj = new Object();

 

     boolean flag = true;

 

     public  void run(){

 

          if(flag){

 

               while(true){

 

                    synchronized(Ticket.class) {

 

                         if(tick>0){

 

                              try{

 

                                  Thread.sleep(10);

 

                              }

 

                              catch(Exception e){  }

 

                              System.out.println(Thread.currentThread().getName()+"....code : "+ tick--);

 

                         }

 

                    }

 

               }

 

          }

 

          else

 

               while(true)

 

                    show();

 

     }

 

     public static synchronized void show(){    //静态同步函数没有显性的锁,但是隐含着 锁:Ticket.class 

 

          if(tick>0){

 

               try{

 

                    Thread.sleep(10);

 

               }catch(Exception e){  }

 

               System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--);

 

          }

 

     }

 

}

 

 

 

class  StaticMethodDemo

 

{

 

     public static void main(String[] args){

 

          Ticket t = new Ticket();

 

          Thread t1 = new Thread(t);

 

          Thread t2 = new Thread(t);

 

          t1.start();

 

          try{

 

              Thread.sleep(10);

 

          }catch(Exception e){  }

 

          t.flag = false;

 

          t2.start();     

 

     }

 

 

 

 


 

 

 

8、多线程应用实例:单例设计模式——懒汉式

 

     懒汉式 的单例设计模式,因存在多线程安全的问题,所以需要使用“同步代码块+双重校验”的方式来解决 

 

     而饿汉式 单例设计模式 不存在 多线程安全的问题,建议多使用

 

    

 

 Demo样例:

 

//饿汉式 单例设计模式 --- 定义时就初始化

 

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(){

 

          if(s==null){

 

               synchronized(Single.class){

 

                    if(s==null){

 

                         //--->A;

 

                         s = new Single();

 

                    }

 

               }

 

          }

 

          return s;

 

     }

 

}

 

 

 


 

9、多线程运行问题 ———— 死锁

 

    在编写多线程功能代码时,若为了解决安全问题而使用了相互嵌套的Synchronized代码块或Synchronized函数,则有可能发生死锁问题。     

 

    编写可发生死锁代码的思路:(这是面试题,请花心思学习一下。当你能写出死锁的程序,自然也就能避免死锁的编码了)

 

        (1)创建并执行两个线程

 

        (2)创建一个可提供两把锁的 锁类 

 

        (3)创建实现Runnable接口的类,在复写的run()方法中编写可通过flag变换执行 的两段不同代码

 

        (4)在两段代码中分别进行Synchronized代码块的嵌套。

 

        (5)在相互嵌套的Synchronized代码块 要分别使用锁类提供的两把不同的锁。

 

    上面是分析的思路,但是在书写时,应该倒个顺序来写。

 

 

 

Demo样例 :

 

class Test implements Runnable

 

{

 

     private boolean flag;

 

     Test(boolean flag){

 

          this.flag = flag;

 

     }

 

     public void run(){

 

          if(flag){

 

               while(true){

 

                    synchronized(MyLock.locka){

 

                         System.out.println(Thread.currentThread().getName()+"...if locka ");

 

                         synchronized(MyLock.lockb){

 

                              System.out.println(Thread.currentThread().getName()+"..if lockb");     

 

                         }

 

                    }

 

               }

 

          }

 

          else{

 

               while(true){

 

                    synchronized(MyLock.lockb){

 

                         System.out.println(Thread.currentThread().getName()+"..else lockb");

 

                         synchronized(MyLock.locka){

 

                              System.out.println(Thread.currentThread().getName()+".....else locka");

 

                         }

 

                    }

 

               }

 

          }

 

     }

 

}

 

 

 

class MyLock

 

{

 

     static Object locka = new Object();

 

     static Object lockb = new Object();

 

}

 

class  DeadLockTest

 

{

 

     public static void main(String[] args) {

 

          Thread t1 = new Thread(new Test(true));

 

          Thread t2 = new Thread(new Test(false));

 

          t1.start();

 

          t2.start();

 

     }

 

 

 

 


 

 

 

10、线程间通信 —— 解决安全问题:等待唤醒机制

 

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

 

        并且通过wait();notify();notifyAll();这五种方法,来控制不同线程在 5种状态 之间的转换,以得符合要求的结果。

 

   在JDK的Object类中,三个方法的释义如下: 

 

         notify() :唤醒在此对象监视器上等待的单个线程。 

 

         notifyAll() :唤醒在此对象监视器上等待的所有线程。 

 

         wait() :在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。 

 

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

 

    

 

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

 

        因为这些方法在操作同步中线程时,都必须要标识它们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。不可以对不同锁中的线程进行唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。 

 

    其具体的应用含义参见下面Demo样例:

 

 

 

Demo样例 : 

 

//需求:两个线程分别向一个资源进行员工数据的输入与输出,并且有两种样式。A:(mike,man); B:(丽丽,女女女女女)。

 

//要求边输入,边打印输出,而且要按照顺序“一条英文,一条中文”的打印 

 

class Res    //被操作资源

 

{

 

     String name;

 

     String sex;

 

     boolean flag = false;

 

}

 

class Input implements Runnable

 

{

 

     private Res r ;

 

     Input(Res r){

 

          this.r = r;

 

     }

 

     public void run(){

 

          int x = 0;

 

          while(true){

 

               synchronized(r){

 

                    if(r.flag)

 

                         try{ 

 

                             r.wait(); 

 

                         }catch(Exception e){ }

 

                    if(x==0){

 

                         r.name="mike";

 

                         r.sex="man";

 

                    }else {

 

                         r.name="丽丽";

 

                         r.sex = "女女女女女";

 

                    }

 

                    x = (x+1)%2;//此句是控制 两种样式 轮换输入的 判断条件。

 

                    r.flag = true;

 

                    r.notify();

 

               }

 

          }

 

     }

 

}

 

class Output implements Runnable

 

{

 

     private Res r ; 

 

     Output(Res r){

 

          this.r = r;

 

     }

 

     public void run(){

 

          while(true){

 

               synchronized(r){

 

                    if(!r.flag)

 

                        try{ 

 

                            r.wait();

 

                        }catch(Exception e){ }

 

                    System.out.println(r.name+"...."+r.sex);

 

                    r.flag = false;

 

                    r.notify();

 

               }

 

          }

 

     }

 

}

 

 

 

class  InputOutputDemo

 

{

 

     public static void main(String[] args) {

 

          Res r = new Res();

 

          Input in = new Input(r);

 

          Output out = new Output(r);

 

          Thread t1 = new Thread(in);

 

          Thread t2 = new Thread(out);

 

          t1.start();

 

          t2.start();

 

     }

 

 

//notifyAll();

 

 

 

 

 

上述代码优化处理 

 

Demo样例 : 

 

class Res

 

{

 

     private String name;

 

     private String sex;

 

     private boolean flag = false;

 

     public synchronized void set(String name,String sex){

 

          if(flag)

 

               try{ this.wait();}catch(Exception e){ }

 

          this.name = name;         

 

          this.sex = sex;

 

          flag = true;

 

          this.notify();

 

     }

 

     public synchronized void out(){

 

          if(!flag)

 

               try{ this.wait();}catch(Exception e){ }

 

          System.out.println(name+"........"+sex);

 

          flag = false;

 

          this.notify();

 

     }

 

}

 

class Input implements Runnable

 

{

 

     private Res r ;

 

     Input(Res r){

 

          this.r = r;

 

     }

 

     public void run(){

 

          int x = 0;

 

          while(true){

 

               if(x==0)    

 

                    r.set("mike","man");    

 

               else 

 

                    r.set("丽丽","女女女女女");    

 

               x = (x+1)%2;

 

          }

 

     }

 

}

 

class Output implements Runnable

 

{

 

     private Res r ; 

 

     Output(Res r){

 

          this.r = r;

 

     }

 

     public void run(){

 

          while(true){

 

               r.out();

 

          }

 

     }

 

}

 

 

 

class  InputOutputDemo2

 

{

 

     public static void main(String[] args) {

 

          Res r = new Res();

 

          new Thread(new Input(r)).start();

 

          new Thread(new Output(r)).start();

 

          /*

 

          Input in = new Input(r);

 

          Output out = new Output(r);

 

          Thread t1 = new Thread(in);

 

          Thread t2 = new Thread(out);

 

          t1.start();

 

          t2.start();

 

          */

 

     }

 

}

 

 

 

 

 


 

 

 

11、线程间通信——多个并发线程的生产者和消费者 (经典示例) 

 

     问题由来:请参见下面的Demo样例 

 

    思考一:对于多个生产者和消费者,为什么要定义while判断标记。

 

            原因:让被唤醒的线程再一次判断标记。 

 

    思考一: 为什么定义notifyAll,

 

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

 

 

 

Demo样例 : 

 

class ProducerConsumerDemo 

 

{

 

     public static void main(String[] args) {

 

          Resource r = new Resource();

 

          Producer pro = new Producer(r);

 

          Consumer con = new Consumer(r);

 

          Thread t1 = new Thread(pro);

 

          Thread t2 = new Thread(pro);

 

          Thread t3 = new Thread(con);

 

          Thread t4 = new Thread(con);

 

          t1.start();

 

          t2.start();

 

          t3.start();

 

          t4.start();

 

     }

 

 

 

 

Demo样例 : 

 

class Resource

 

{

 

     private String name;

 

     private int count = 1;

 

     private boolean flag = false;

 

       //  t1    t2

 

     public synchronized void set(String name){

 

          while(flag)

 

               try{ this.wait();}catch(Exception e){}//t1(放弃资格)  t2(获取资格)

 

          this.name = name+"--"+count++;

 

          System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);

 

          flag = true;

 

          this.notifyAll();

 

     }

 

     

 

     //  t3   t4  

 

     public synchronized void out(){

 

          while(!flag)

 

               try{ wait();}catch(Exception e){}//t3(放弃资格) t4(放弃资格)

 

          System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);

 

          flag = false;

 

          this.notifyAll();

 

     }

 

}

 

class Producer implements Runnable

 

{

 

     private Resource res;

 

     Producer(Resource res){

 

          this.res = res;

 

     }

 

     public void run(){

 

          while(true){

 

               res.set("+商品+");

 

          }

 

     }

 

}

 

class Consumer implements Runnable

 

{

 

     private Resource res;

 

     Consumer(Resource res){

 

          this.res = res;

 

     }

 

     public void run(){

 

          while(true){

 

               res.out();

 

          }

 

     }

 

}

 

 

 

 

 

 

 


 

 

 

12、线程间通信——多个并发线程的 生产者和消费者——JDK5.0 升级版:Lock 和 Condition 

 

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

 

    a.将同步Synchronized替换成现实Lock操作。

 

    b.将Object中的wait,notify notifyAll,替换了Condition对象。

 

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

 

    对比如下:

 

        Lock:替代了Synchronized

 

         lock 

 

         unlock

 

         newCondition()

 

         Condition:替代了Object wait notify notifyAll,实现了本方只唤醒对方操作。 

 

         await();

 

         signal();

 

         signalAll();

 

 

 

Demo样例 : 

 

import java.util.concurrent.locks.*;

 

class ProducerConsumerDemo2 

 

{

 

     public static void main(String[] args){

 

          Resource r = new Resource();

 

          Producer pro = new Producer(r);

 

          Consumer con = new Consumer(r);

 

          Thread t1 = new Thread(pro);

 

          Thread t2 = new Thread(pro);

 

          Thread t3 = new Thread(con);

 

          Thread t4 = new Thread(con);

 

          t1.start();

 

          t2.start();

 

          t3.start();

 

          t4.start();

 

     }

 

 

 

 

Demo样例 : 

 

class Resource

 

{

 

     private String name;

 

     private int count = 1;

 

     private boolean flag = false;

 

       //  t1    t2

 

     private Lock lock = new ReentrantLock();

 

     private Condition condition_pro = lock.newCondition();

 

     private Condition condition_con = lock.newCondition();

 

 

 

     public  void set(String name)throws InterruptedException

 

     {

 

          lock.lock();

 

          try{

 

               while(flag)

 

                    condition_pro.await();//t1,t2

 

               this.name = name+"--"+count++;

 

               System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);

 

               flag = true;

 

               condition_con.signal();

 

          }finally{

 

               lock.unlock();//释放锁的动作一定要执行。

 

          }

 

     }

 

 

 

     //  t3   t4  

 

     public  void out()throws InterruptedException{ 

 

          lock.lock();

 

          try{

 

               while(!flag)

 

                    condition_con.await();

 

               System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);

 

               flag = false;

 

               condition_pro.signal();

 

          }finally{

 

               lock.unlock();

 

          }     

 

     }

 

}

 

class Producer implements Runnable

 

{

 

     private Resource res;

 

     Producer(Resource res){

 

          this.res = res;

 

     }

 

     public void run(){

 

          while(true){

 

               try{

 

                    res.set("+商品+");

 

               }catch (InterruptedException e){  }

 

          }

 

     }

 

}

 

class Consumer implements Runnable

 

{

 

     private Resource res;

 

     Consumer(Resource res){

 

          this.res = res;

 

     }

 

     public void run(){

 

          while(true){

 

               try{

 

                res.out();

 

               }

 

               catch (InterruptedException e){   }

 

          }

 

     }

 

 

 

 


 

 

 

13、多线程————停止线程

 

    Thread类中的stop方法已经过时。

 

    那么如何停止线程?

 

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

 

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

 

    Thread类提供该方法 interrupt(); 

 

 

 

Demo样例 : 

 

class StopThread implements Runnable

 

{

 

     private boolean flag =true;

 

     public  void run(){

 

          while(flag){

 

               System.out.println(Thread.currentThread().getName()+"....run");

 

          }

 

     }

 

     public void changeFlag(){

 

          flag = false;

 

     }

 

 

class  StopThreadDemo

 

{

 

     public static void main(String[] args) {

 

      StopThread st = new StopThread();

 

     

 

      Thread t1 = new Thread(st);

 

      Thread t2 = new Thread(st);

 

     

 

      t1.setDaemon(true);

 

      t2.setDaemon(true);

 

      t1.start();

 

      t2.start();

 

      int num = 0;

 

      while(true){

 

           if(num++ == 60){

 

                //st.changeFlag();

 

                //t1.interrupt();

 

                //t2.interrupt();

 

                break;

 

           }

 

           System.out.println(Thread.currentThread().getName()+"......."+num);

 

      }

 

      System.out.println("over");

 

     }

 

}

 

  

 


 

 14、守护线程 Join / 线程优先级  /  yield 方法   

 

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

 

    线程优先级 //t1.setPriority(Thread.MAX_PRIORITY); 

 

    yield()方法:主要是用来暂时出让一次CPU执行权,可实现隔次执行 交替的效果。

 

 

 

Demo样例 : 

 

class Demo implements Runnable

 

{

 

     public void run(){

 

          for(int x=0; x<70; x++){

 

               System.out.println(Thread.currentThread().toString()+"....."+x);

 

               Thread.yield();

 

          }

 

     }

 

 

class  JoinDemo

 

{

 

     public static void main(String[] args) throws Exception{

 

          Demo d = new Demo();

 

          Thread t1 = new Thread(d);

 

          Thread t2 = new Thread(d);

 

          t1.start();

 

         

 

          //t1.setPriority(Thread.MAX_PRIORITY);

 

          t2.start();

 

          //t1.join();

 

          for(int x=0; x<80; x++){

 

               //System.out.println("main....."+x);

 

          }

 

          System.out.println("over");

 

     }

 

 

 

 


 

 15、多线程在实际应用中的演示

 

 

 

Demo样例 : 

 

class ThreadTest 

 

{

 

     public static void main(String[] args){ 

 

      new Thread(){

 

           public void run(){

 

                for(int x=0; x<100; x++){

 

                     System.out.println(Thread.currentThread().getName()+"....."+x);

 

                }

 

           }

 

      }.start();     

 

     

 

      for(int x=0; x<100; x++){

 

           System.out.println(Thread.currentThread().getName()+"....."+x);

 

      }

 

      Runnable r  = new Runnable(){

 

           public void run(){

 

                for(int x=0; x<100; x++){

 

                     System.out.println(Thread.currentThread().getName()+"....."+x);

 

                }

 

           }

 

      };

 

      new Thread(r).start(); 

 

      //new Test1().start();

 

     }

 

}

 

/*

 

class Test1 extends Thread

 

{

 

     public void run(){

 

          for(int x=0; x<100; x++){

 

               System.out.println(Thread.currentThread().getName()+"....."+x);

 

          }

 

     }

 

}

 

*/

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 大小: 49.7 KB
5
1
分享到:
评论
3 楼 寻找方向 2014-05-10  
很好,很强大,很仔细,学习了!
2 楼 Even2012 2013-05-07  
非常感谢您的肯定!我会继续整理——可方便大家快速查阅的技术笔记。
1 楼 niedj 2013-03-07  
值得一看..

相关推荐

    JAVA 多线程学习笔记

    这篇学习笔记将深入探讨Java多线程的核心概念、实现方式以及相关工具的使用。 一、多线程基础 1. 线程与进程:在操作系统中,进程是资源分配的基本单位,而线程是程序执行的基本单位。每个进程至少有一个主线程,...

    java多线程笔记

    在多线程环境下,多个线程可以并行地在单个进程中执行,使得程序能够同时处理多项任务。 Java中的线程是通过`Thread`类或实现`Runnable`接口来创建的。你可以直接继承`Thread`类并重写`run()`方法,或者创建一个...

    马士兵多线程笔记.zip

    马士兵是一名知名的IT讲师,他的多线程训练营致力于帮助学员深入理解和掌握多线程技术。以下是对马士兵多线程笔记的详细解析。 1. **多线程基础**:多线程是指一个应用程序中同时执行多个线程(即任务)的能力。...

    张孝祥Java多线程与并发库高级应用笔记

    张孝祥的Java多线程与并发库高级应用笔记涵盖了从传统线程技术到JDK1.5并发库的全面内容,不仅加深了对线程基本原理的认识,还介绍了现代Java并发编程的最佳实践。对于希望提升多线程编程技能的Java开发者来说,这是...

    Java多线程学习笔记

    ### Java多线程学习笔记 #### 一、线程的基本概念 在计算机科学中,**线程**(Thread)是程序执行流的最小单位。一个标准的程序只能做一件事情,而通过多线程技术,可以让程序同时处理多个任务。在Java中,线程是...

    java多线程笔记全手打

    本笔记全面涵盖了多线程的学习,包括基础理论和实践代码,旨在帮助开发者深入理解并掌握Java多线程技术。 一、线程基础知识 线程是操作系统分配CPU时间的基本单位,一个进程中可以包含多个线程。Java通过`Thread`类...

    马士兵多线程训练营笔记

    10. **实战经验**:通过实际案例分析,学习如何在项目中有效地使用多线程和同步技术,提高程序性能和稳定性。 通过马士兵的多线程训练营笔记,开发者不仅可以学习到多线程的基本概念,还能掌握高级并发编程技巧,这...

    Java多线程详解(超详细)_狂神说笔记完整版_项目代码_适合小白随课程学习

    在Java编程中,多线程是一种重要的技术,它使得程序能够同时执行多个任务,提高系统的效率和响应性。本教程将详细讲解Java中的多线程概念,包括线程的创建、状态、同步以及高级主题,旨在帮助初学者逐步掌握这一关键...

    java线程学习笔记

    Java 线程学习笔记 Java 线程创建有两种方法: 1. 继承 Thread 类,重写 run 方法:通过继承 Thread 类并重写 run 方法来创建线程,这种方法可以使线程具有自己的执行逻辑。 2. 实现 Runnable 接口:通过实现 ...

    多线程笔记.docx

    在编写多线程程序时,需要关注线程安全、竞态条件、死锁等问题,合理使用同步机制,如synchronized、volatile、java.util.concurrent包下的工具类等,以保证程序的正确性和稳定性。此外,线程间的协作(如wait()、...

    狂神说多线程详解.rar

    《狂神说多线程详解》是一份深入探讨多线程技术的资源包,其中包含了对多线程编程的详尽解析。多线程是现代计算机编程中的一个重要概念,尤其在处理高性能计算、并发操作以及实时系统时,多线程技术显得尤为重要。它...

    java多线程学习笔记

    这篇文档和源代码将深入探讨Java多线程的各个方面,旨在帮助学习者掌握这一关键技术。 首先,我们要了解Java中创建线程的两种主要方式:继承Thread类和实现Runnable接口。继承Thread类时,我们需要重写run()方法,...

    线程技术学习笔记.docx

    线程技术是计算机科学中的重要概念,特别是在Java编程语言中,多线程是实现高效并发执行的关键。本篇文章将深入探讨线程的基础知识,帮助初学者建立完整的线程技术知识架构。 首先,线程和进程是两个核心概念。线程...

    多线程学习笔记.docx

    在多线程编程中,进程和线程是两个核心概念。进程是操作系统资源分配的基本单位,每个独立执行的程序都对应一个进程。而线程则是程序执行的最小单元,是进程内部的一条执行路径。多线程是指在一个应用程序中存在多个...

    多线程笔记_java/多线程_

    本文档将全面解析多线程的基础知识,从简单到复杂,帮助开发者深入理解并掌握这一核心技术。 一、多线程基础 1.1 线程与进程 线程是操作系统分配处理器时间的基本单元,而进程则是资源分配的基本单位。一个进程...

    多线程-狂神说Java学习笔记

    本学习笔记将深入探讨Java多线程的相关知识,包括其原理、实现方式、同步机制以及常见问题。 ### 一、多线程的基本概念 多线程是指在一个程序中存在两个或更多的执行线程,这些线程共享同一内存空间,但各自拥有...

    java多线程反射泛型及正则表达式学习笔记和源码.zip

    这个压缩包包含的“java多线程反射泛型及正则表达式学习笔记和源码”正是针对这些关键知识点的学习资料。 首先,我们来详细探讨多线程。在Java中,多线程允许程序同时执行多个不同的任务,提高了程序的并发性和效率...

    JUC学习笔记(Java多线程)

    总的来说,JUC学习笔记涵盖了Java多线程编程的主要方面,包括线程的创建与管理、同步机制、并发容器以及协调工具的使用,这些都是提升Java并发编程能力的关键知识点。通过深入理解和熟练应用这些工具,开发者可以更...

Global site tag (gtag.js) - Google Analytics