`

多线程(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  
值得一看..

相关推荐

    线程安全你还在用synchronized?

    你还在用synchronized?线程安全相关知识深入剖析

    java多线程笔记

    Java线程:线程名称的设定及获取 10 Java线程:线程栈模型与线程的变量 12 Java线程:线程的调度-休眠 13 Java线程:线程的调度-优先级 16 Java线程:线程的调度-让步 19 Java线程:线程的调度-合并 22 Java线程:...

    多线程系列相关的技术要点

    2. Java多线程学习(二)synchronized关键字(1) 3. Java多线程学习(二)synchronized关键字(2) 4. Java多线程学习(三)volatile关键字 5. Java多线程学习(四)等待/通知(wait/notify)机制 6. Java多...

    synchronized 实现多线程 implements Runnable

    一个简单的多线程代码示例,Java实现,用于实现同一时刻,只允许一个线程调用执行的代码块或类,即synchronized的如何使用(多线程实现),实现 Runnable

    java多线程中synchronized关键字的用法

    java多线程中synchronized关键字的用法 解压密码 www.jiangyea.com

    Synchronized锁在Spring事务管理下线程不安全

    Synchronized锁在Spring事务管理下,导致线程不安全。

    JUC多线程学习个人笔记

    原子操作:JUC提供了一些原子操作类,如AtomicInteger、AtomicLong等,可以实现线程安全的原子操作,避免了使用synchronized关键字的性能损耗。 锁机制:JUC提供了Lock接口和Condition接口,可以实现更细粒度的锁...

    java-多线程学习代码.zip

    多线程的学习的笔记 Thread1:继承Thread类 * Thread2:继承Runnable接口 * * ThreadMethod:一些Thread常见方法 * ThreadTestDome1 练习:创建两个线程 其中一个线程遍历100以内的偶数 另一个遍历一百内奇数 ...

    synchronized与单例的线程安全

    synchronized与单例的线程安全问题,博客地址:https://www.jianshu.com/p/486ed9c8662a

    java多线程安全性基础介绍.pptx

    java多线程安全性基础介绍 线程安全 正确性 什么是线程安全性 原子性 竞态条件 i++ 读i ++ 值写回i 可见性 JMM 由于cpu和内存加载速度的差距,在两者之间增加了多级缓存导致,内存并不能直接对cpu可见。 ...

    java 多线程synchronized互斥锁demo

    一个多线程访问的同一个资源,java synchronized互斥锁的用法,android和此用法一致。

    java多线程设计模式详解(PDF及源码)

    单线程程序 多线程程序 Thread类的run方法和start方法 线程的启动 线程的启动(1)——利用Thread类的子类 线程的启动(2)——利用Runnable接口 线程的暂时停止 线程的共享互斥 synchronized方法 synchronized阻挡 ...

    java多线程编程_java多线程_

    2.讲解了在多线程中对并发访问的控制, 主要就是synchronized的使用, 由于此关键字在使用上非常灵活, 所以书中用了很多案例来介绍此关键字的使用, 为读者学习同步相关内容打好坚实的基础。3.介绍线程并不是孤独的...

    Java线程安全synchronized

     如果一个资源(变量,对象,文件,数据库)可以同时被很多线程使用会出现数据不一致问题,也是我们说的线程安全问题。这样的资源被称为共享资源或临界区。  举个例子:  一个共享变量m,现在有两个线程同时对...

    Stack 线程安全问题

    栈的线程安全问题 的解决代码 push pop synchronized THread

    Java、Android线程安全与多线程数据同步

    NoHttp核心架构之多线程通信、线程安全、线程同步;synchronized锁,Lock锁;具体讲解请移步:http://blog.csdn.net/yanzhenjie1003/article/details/50992468

    java线程学习笔记

    1.2 线程构造器Threat 2 1.3 执行器Executor 2 1.4 任务中返回值Callable接口 3 1.5 休眠 6 1.6 让步 6 1.7 优先级 6 1.8 后台线程(daemon) 6 1.9 加入线程(join) 8 1.10 捕获异常(UncaughtExceptionHandler) ...

    Java多线程与线程安全实践-基于Http协议的断点续传的实现.rar

    可以使用Java中的同步机制,如使用synchronized关键字或者使用线程安全的集合类来保证多线程操作的安全性。 实现步骤: 创建一个下载管理器类,用于管理下载任务和线程池。 在下载管理器中实现多线程下载的逻辑,...

    Java、Android多线程、线程安全、线程同步

    NoHttp核心架构之多线程通信、线程安全、线程同步;synchronized锁,Lock锁;具体讲解请移步博客:http://blog.csdn.net/yanzhenjie1003/article/details/50992468

    使用synchronized实现多线程同步.pdf

    使用synchronized实现多线程同步.pdf

Global site tag (gtag.js) - Google Analytics