zoukankan      html  css  js  c++  java
  • 多线程

    第一种创建方式:继承Thread类

    复写Tread的run()方法,调用start()开启线程并执行

     1 /**
     2 *Xiancheng2继承Thread类,实现run()方法
     3 *main即为主线程
     4 *线程随机访问
     5 */
     6 class XianCheng2 extends Thread
     7 {
     8     public void run(){
     9         for(int x=0;x<500;x++)
    10             System.out.println("run---"+x);
    11     }
    12 }
    13 class XianCheng1 
    14 {
    15     public static void main(String[] args){
    16         XianCheng2 x=new XianCheng2();
    17         //开启线程并执行
    18         x.start();
    19         for(int i=0;i<500;i++){
    20             System.out.println("mian----"+i);
    21         }
    22     }
    23 }
    View Code

    设置获取线程的名称:构造方法(name),void setName();this.getName(),Thread.currentThread().getName()(标准写法);

     1  1 /**
     2  2 *需求:1.通过两种方式设置线程的名字
     3  3 *需求:2.通过两种方式获取线程的名字
     4  4 */
     5  5 class XianCheng2 extends Thread
     6  6 {
     7  7     //1.1构造方法设置名字
     8  8     XianCheng2(String name){
     9  9         super(name);
    10 10     }
    11 11     public void run(){
    12 12     for(int i=0;i<30;i++)
    13 13         //2.1通过getName()方法获取当前线程的名字
    14 14         System.out.println(this.getName()+"-----"+i);
    15 15     }
    16 16 }
    17 17 class XianCheng3 extends Thread
    18 18 {
    19 19     public void run(){
    20 20         for(int i=0;i<30;i++){
    21 21             //2.2通过Thread的静态方法currentThread()获取当前对象的引用,从而获取名字
    22 22             System.out.println(XianCheng3.currentThread().getName()+"-----"+i);
    23 23         }
    24 24     }
    25 25 }
    26 26 class XianCheng1 
    27 27 {
    28 28     public static void main(String[] args){
    29 29         new XianCheng2("one").start();
    30 30         XianCheng3 x=new XianCheng3();
    31 31         //1.2通过setName()方法设置线程名称
    32 32         x.setName("two");
    33 33         x.start();
    34 34 
    35 35         for(int i=0;i<30;i++)
    36 36             //这里不能使用this!!
    37 37             System.out.println(Thread.currentThread().getName()+"-----"+i);
    38 38     }
    39 39 }
    View Code

    思考:如果XianCheng2这个类已经是某个类的子类,还能通过继承的方式创建线程吗? 

    第二种方式:实现Runnable接口

    显然,限制于单继承,XianCheng2无法再继承Thread,现在可以通过实现runnable接口创建线程!

    卖票小程序:

     1  1 /**
     2  2 *三个售票员同时卖票,共100张
     3  3 */
     4  4 class Ticketer implements Runnable
     5  5 {
     6  6     private int num=100;
     7  7     public void run(){
     8  8         while(num>0){
     9  9             /*下句将会出现问题,出现0票数和-1票数
    10 10             当num=1时,假设第一个线程执行到wihle,条件符合,这时候cpu切换到第二个线程,执行到while
    11 11             条件也符合,但始终剩下的输出语句还会执行,所以当这种假设出现,0则出现,这是不被期望的
    12 12             */
    13 13             //try{Thread.sleep(10);}catch(InterruptedException e){}
    14 14             //进程名...票号
    15 15             System.out.println(Thread.currentThread().getName()+"..."+num--);
    16 16         }
    17 17     }
    18 18 
    19 19 }
    20 20 class RunnableDemo 
    21 21 {
    22 22     public static void main(String[] args) 
    23 23     {
    24 24         Ticketer t=new Ticketer();
    25 25         //Thread(runnable,name)
    26 26         new Thread(t,"T-one").start();
    27 27         new Thread(t,"T-two").start();
    28 28         new Thread(t,"T-three").start();
    29 29     }
    30 30 }
    View Code

     注意:当执行上面的程序加上第13行代码的时候,程序就容易出问题了!!当有多个线程操作某个共有数据的时候,一定要警惕,程序时候会出问题!!

     思考:如何控制某代码块若被某线程执行,则执行完,其他线程无法执行?

    synchronized

    作用:加锁

    用法1:synchronized(obj),方法体内封装要加锁的代码块,obj参数即为使用锁的对象

     1 1 /**
     2  2 *三个售票员同时卖票,共100张
     3  3 */
     4  4 class Ticketer implements Runnable
     5  5 {
     6  6     Object obj=new Object();//synchronized(obj)
     7  7     private int num=100;
     8  8     public void run(){
     9  9         while(num>0){
    10 10             //加锁
    11 11         synchronized(obj){
    12 12             if(num>0){
    13 13                 try{Thread.sleep(10);}catch(InterruptedException e){}
    14 14                 System.out.println(Thread.currentThread().getName()+"..."+num--);
    15 15             }
    16 16         }
    17 17         }
    18 18     }
    19 19 
    20 20 }
    21 21 class RunnableDemo 
    22 22 {
    23 23     public static void main(String[] args) 
    24 24     {
    25 25         Ticketer t=new Ticketer();
    26 26         //Thread(runnable,name)
    27 27         new Thread(t,"T-one").start();
    28 28         new Thread(t,"T-two").start();
    29 29         new Thread(t,"T-three").start();
    30 30     }
    31 31 }
    View Code

    用法2:作为关键字修饰非静态函数,函数体即为加锁的代码块,此时锁是this

     1  1 /**
     2  2 *三个售票员同时卖票,共100张
     3  3 */
     4  4 class Ticketer implements Runnable
     5  5 {
     6  6     private int num=100;
     7  7     public void run(){
     8  8         while(num>0){
     9  9             show();
    10 10         }
    11 11     }
    12 12         //修饰方法体,加锁
    13 13     public synchronized void show(){
    14 14             if(num>0){
    15 15                 try{Thread.sleep(10);}catch(InterruptedException e){}
    16 16                 System.out.println(Thread.currentThread().getName()+"..."+num--);
    17 17             }    
    18 18     }
    19 19 
    20 20 }
    21 21 class RunnableDemo 
    22 22 {
    23 23     public static void main(String[] args) 
    24 24     {
    25 25         Ticketer t=new Ticketer();
    26 26         //Thread(runnable,name)
    27 27         new Thread(t,"T-one").start();
    28 28         new Thread(t,"T-two").start();
    29 29         new Thread(t,"T-three").start();
    30 30     }
    31 31 }
    View Code

    程序验证是this:

     1  1 /**
     2  2 *两个售票员同时卖票,共100张
     3  3 *验证:synchronized修饰的函数用的锁是this
     4  4 */
     5  5 class Ticketer implements Runnable
     6  6 {
     7  7     private int num=100;
     8  8     boolean flag=true;
     9  9     Object obj=new Object();
    10 10     public void run(){
    11 11         if(flag){
    12 12             while(num>0){
    13 13                 synchronized(obj){//当这里传入this时才能正常卖完票,否则0票出现
    14 14                 if(num>0){
    15 15                     try{Thread.sleep(10);}catch(InterruptedException e){}
    16 16                     System.out.println(Thread.currentThread().getName()+"...hei..."+num--);
    17 17                 }                    
    18 18                 }
    19 19             }
    20 20         }
    21 21         else 
    22 22             while(num>0)
    23 23                 show();
    24 24     }
    25 25         //修饰方法体,加锁
    26 26     public synchronized void show(){
    27 27         if(num>0){
    28 28             try{Thread.sleep(10);}catch(InterruptedException e){}
    29 29             System.out.println(Thread.currentThread().getName()+"...hi..."+num--);
    30 30         }    
    31 31     }
    32 32 
    33 33 }
    34 34 class RunnableDemo 
    35 35 {
    36 36     public static void main(String[] args) 
    37 37     {
    38 38         Ticketer t=new Ticketer();
    39 39         //Thread(runnable,name)
    40 40         new Thread(t,"T-one").start();
    41 41         //让主线程休息10毫秒,这时只有T-one在跑,且flag=true,
    42 42         //当执行到while时”根本停不下来“   num不为0的情况下
    43 43         try{Thread.sleep(10);}catch(InterruptedException e){}
    44 44         //10毫秒过后,主线程醒了,下句执行,falg=false,
    45 45         //然后T-one开启,因false,T-one执行else部分,执行到while也停不下来
    46 46         //所以两个进程在10毫秒之后就开始不停的切换
    47 47         t.flag=false;
    48 48         new Thread(t,"T-two").start();
    49 49     }
    50 50 }
    View Code

    0票出现:如果是一个锁,那么不会出现0票,然而出现了,说明了函数体的锁不是obj,当synchronized(this)时,正确卖票,此时说明是同一把锁,即函数锁是this!!

     为何强调非静态?如果是静态方法,则是类.静态方法(),轮不到this,此时锁是谁?

    静态类加载进内存时,不会创建本类对象,唯一的对象就是Class对象-》字节码文件对象:类名.class,而这个锁就是类名.class

     1 /**
     2 *两个售票员同时卖票,共100张
     3 *验证:synchronized修饰的函数用的锁是this
     4 */
     5 class Ticketer implements Runnable
     6 {
     7     private static int num=100;
     8     boolean flag=true;
     9     public void run(){
    10         if(flag){
    11             while(num>0){
    12                 synchronized(Ticketer.class){//传入字节码对象
    13                 if(num>0){
    14                     try{Thread.sleep(10);}catch(InterruptedException e){}
    15                     System.out.println(Thread.currentThread().getName()+"...hei..."+num--);
    16                 }                    
    17                 }
    18             }
    19         }
    20         else 
    21             while(num>0)
    22                 show();
    23     }
    24         //修饰方法体,加锁
    25     public static synchronized void show(){
    26         if(num>0){
    27             try{Thread.sleep(10);}catch(InterruptedException e){}
    28             System.out.println(Thread.currentThread().getName()+"...hi..."+num--);
    29         }    
    30     }
    31 
    32 }
    33 
    34 class StaticSynchronized 
    35 {
    36     public static void main(String[] args) 
    37     {
    38         Ticketer t=new Ticketer();
    39         //Thread(runnable,name)
    40         new Thread(t,"T-one").start();
    41         //让主线程休息10毫秒,这时只有T-one在跑,且flag=true,
    42         //当执行到while时”根本停不下来“   num不为0的情况下
    43         try{Thread.sleep(10);}catch(InterruptedException e){}
    44         //10毫秒过后,主线程醒了,下句执行,falg=false,
    45         //然后T-one开启,因false,T-one执行else部分,执行到while也停不下来
    46         //所以两个进程在10毫秒之后就开始不停的切换
    47         t.flag=false;
    48         new Thread(t,"T-two").start();
    49     }
    50 }
    View Code

     补充单例模式:http://blog.csdn.net/jason0539/article/details/23297037

     1 /**
     2 需求:单例模式恶汉式SingleOne与懒汉式SingleTow
     3 */
     4 //恶汉式,在类初始化时创建一个唯一的对象
     5 class SingleOne
     6 {
     7     private SingleOne(){}
     8     //初始化时创建一个唯一对象
     9     private static final SingleOne single=new SingleOne();
    10     //通过静态方法获取这个对象
    11     public static SingleOne getInstance(){
    12         return single;
    13     }
    14     
    15 }
    16 //懒汉式:在类初始化时不创建对象->延迟加载
    17 //然而面临多线程时,懒汉式可能会出现问题->不再单例
    18 class SingleTwo
    19 {
    20     private SingleTwo(){}
    21     private static SingleTwo single=null;
    22     public static SingleTwo getInstance(){
    23         //如果对象还没建立,则同步建立,双重if减少使用锁为1次
    24         if(single==null){
    25             synchronized(SingleTwo.class){//注意,这里是静态的,锁是类文件字节码
    26                 if(single==null)
    27                     single=new SingleTwo();
    28             }
    29         }
    30         return single;
    31     }
    32 }
    View Code

    死锁

    在线程级考虑死锁:线程T1拿到锁a的时候想拿锁b,线程T2拿到锁b的时候想拿到锁a,这样他们就锁上了!!

    考虑不死锁:在T1拿到a的时候,又继续拿到了b,这时候T2干等着,T1用完之后T2就可以用了

    死锁小程序:

     1 /**
     2 定义两个同步嵌套同步的锁造成死锁
     3 */
     4 class DeadLoack implements Runnable
     5 {
     6     boolean flag=true;
     7     DeadLoack(boolean flag){
     8         this.flag=flag;
     9     }
    10     public void run(){
    11         if(flag)
    12         {
    13             //得锁a
    14             synchronized(Loack.a){
    15                 System.out.println(Thread.currentThread().getName()+"..."+"a");
    16                 //得锁b
    17                 synchronized(Loack.b){
    18                     System.out.println(Thread.currentThread().getName()+"..."+"a2");
    19                 }
    20             }
    21         }
    22         else
    23         {
    24             //得锁b
    25             synchronized(Loack.b){
    26                 System.out.println(Thread.currentThread().getName()+"..."+"b");
    27                 //得锁a
    28                 synchronized(Loack.a){
    29                     System.out.println(Thread.currentThread().getName()+"..."+"b2");
    30                 }
    31             }
    32         }
    33     }
    34 }
    35 //定义两把锁
    36 class Loack
    37 {
    38     static Object a=new Object();
    39     static Object b=new Object();
    40 }
    41 
    42 class DeadLoackDemo
    43 {
    44     public static void main(String[] args) 
    45     {
    46         DeadLoack d1=new DeadLoack(true);
    47         DeadLoack d2=new DeadLoack(false);
    48         new Thread(d1,"one").start();
    49         //加上下句,基本上就不会死锁了,在10毫秒内,线程d1完全可以得到锁b
    50         //try{Thread.sleep(10);}catch(Exception e){}
    51         new Thread(d2,"two").start();
    52 
    53     }
    54 }
    View Code

    线程之间的通信 

    以下代码试图:Input对象的信息->Output对象信息   循环执行  试图得到结果{李一男 男}或{liernv girl}

     1 /**
     2 试图:线程a输入数据{李一男 0}或{liernv 1},线程b输出数据{李一男 0}或{liernv 1}
     3 */
     4 class Resource
     5 {
     6     String name;
     7     int sex;
     8 }
     9 class Input implements Runnable
    10 {
    11     Resource r;
    12     //通过构造方法传入资源对象的引用,从而实现让多个线程可以共享同一对象
    13     Input(Resource r){
    14         this.r=r;
    15     }
    16     public void run(){
    17         //
    18         r.sex=0;
    19         while(true){
    20             if(r.sex==0){
    21                 r.name="李一男";
    22             }    
    23             else{
    24                 r.name="liernv";
    25             }
    26             r.sex=(r.sex+1)%2;
    27         }
    28         
    29     }
    30 }
    31 class Output implements Runnable
    32 {
    33     Resource r;
    34     Output(Resource r){
    35         this.r=r;
    36     }
    37     public void run(){
    38         //
    39         while(true){
    40             String x=(r.sex==0)?"男":"girl";
    41             System.out.println(r.name+"..."+x);
    42         }
    43     }
    44 }
    45 class Correspondence 
    46 {
    47     public static void main(String[] args) 
    48     {
    49         Resource r=new Resource();
    50         Input in=new Input(r);
    51         Output out=new Output(r);
    52         new Thread(in).start();
    53         new Thread(out).start();
    54     }
    55 }
    View Code

    然而得到的数据并不是说期望的:输出的李一男时男时女。。

    分析:假设某时刻状态  liernv girl,此时Input执行了写操作->李一男 girl ,此时还没来的及将girl 写为 男,Output已经开始读:李一男 girl

    改进:将读和写操作用同一个同步锁锁起来,那用哪一个锁呢?----最好是用临界资源,即共同操作的对象!

     1 /**
     2 试图:线程a输入数据{李一男 0}或{liernv 1},线程b输出数据{李一男 0}或{liernv 1}
     3 */
     4 class Resource
     5 {
     6     String name;
     7     int sex;
     8 }
     9 class Input implements Runnable
    10 {
    11     Resource r;
    12     //通过构造方法传入资源对象的引用,从而实现让多个线程可以共享同一对象
    13     Input(Resource r){
    14         this.r=r;
    15     }
    16     public void run(){
    17         //
    18         boolean x=true;
    19         while(true){
    20             synchronized(r){//同步锁
    21                 if(x){
    22                     r.name="李一男";r.sex=0;x=false;
    23                 }    
    24                 else{
    25                     r.name="liernv";r.sex=1;x=true;
    26                 }
    27             }
    28         }
    29         
    30     }
    31 }
    32 class Output implements Runnable
    33 {
    34     Resource r;
    35     Output(Resource r){
    36         this.r=r;
    37     }
    38     public void run(){
    39         //
    40         while(true){
    41             synchronized(r){//同步锁
    42                 String x=(r.sex==0)?"男":"girl";
    43                 System.out.println(r.name+"..."+x);
    44             }
    45         }
    46     }
    47 }
    48 class Correspondence 
    49 {
    50     public static void main(String[] args) 
    51     {
    52         Resource r=new Resource();
    53         Input in=new Input(r);
    54         Output out=new Output(r);
    55         new Thread(in).start();
    56         new Thread(out).start();
    57     }
    58 }
    View Code

    考虑:做这样一件事情,如果临界资源存在,则不能执行Input,只能执行Output;当临界资源不存在,则只能执行Input,不能执行Output!

    多线程-等待唤醒机制

     1 /**
     2 需求:Input和Output同步,临界不空则不Input,临界空则不Output
     3 */
     4 class Resource
     5 {
     6     String name;
     7     int sex;
     8     boolean flag=false;
     9 }
    10 class Input implements Runnable
    11 {
    12     Resource r;
    13     //通过构造方法传入资源对象的引用,从而实现让多个线程可以共享同一对象
    14     Input(Resource r){
    15         this.r=r;
    16     }
    17     public void run(){
    18         //
    19         boolean x=true;
    20         while(true){
    21             synchronized(r){//同步锁
    22                 //如果有货,则等待
    23                 if(r.flag)
    24                     try{r.wait();}catch(Exception e){}
    25                 //
    26                 if(x){
    27                     r.name="李一男";r.sex=0;x=false;
    28                 }    
    29                 else{
    30                     r.name="liernv";r.sex=1;x=true;
    31                 }
    32                 //change
    33                 r.flag=true;
    34                 //唤醒output
    35                 r.notify();
    36             }
    37         }
    38         
    39     }
    40 }
    41 class Output implements Runnable
    42 {
    43     Resource r;
    44     Output(Resource r){
    45         this.r=r;
    46     }
    47     public void run(){
    48         //
    49         while(true){
    50             synchronized(r){//同步锁
    51                 //如果没货,这等待
    52                 if(!r.flag) 
    53                     try{r.wait();}catch(Exception e){}
    54                 //
    55                 String x=(r.sex==0)?"男":"girl";
    56                 System.out.println(r.name+"..."+x);
    57                 //change
    58                 r.flag=false;
    59                 //唤醒input
    60                 r.notify();
    61             }
    62         }
    63     }
    64 }
    65 class Correspondence 
    66 {
    67     public static void main(String[] args) 
    68     {
    69         Resource r=new Resource();
    70         Input in=new Input(r);
    71         Output out=new Output(r);
    72         new Thread(in).start();
    73         new Thread(out).start();
    74     }
    75 }
    View Code

    注意:

    1.wait(),notify(),notifyAll()是声明在Object类中的!why?wait和notify是针对同步的,同步必须要锁,锁必须要对象,而wait和notif也必须要指明锁,锁对象可以任意,那只能是在Object中定义

    2.在使用wait,notify时,必须指明同步锁对象!(r.wait())?不然我怎么知道哪个线程wait,notify哪个线程!

    3.public final void wait()throws InterruptedException,所以需要对异常进行处理!

    考虑:写操作和读操作两个方法给谁合适?

    代码优化

     1 /**
     2 需求:1.资源Resource,具有同步读写方法
     3 需求:2.Input和Output实现Runnable接口,启用两个线程
     4 */
     5 class Resource
     6 {
     7     private String name;
     8     private String sex;
     9     private boolean flag=false;
    10     //属性私有,通过set()实现同步写
    11     public synchronized void set(String name,String sex){
    12         if(flag)
    13             try{this.wait();}catch(Exception e){}
    14         this.name=name;
    15         this.sex=sex;
    16         flag=true;
    17         this.notify();
    18     }
    19     //通过out()实现同步读
    20     public synchronized void out(){
    21         if(!flag)
    22             try{this.wait();}catch(Exception e){}
    23         System.out.println(name+"..."+sex);
    24         flag=false;
    25         this.notify();
    26     }
    27 }
    28 class Input implements Runnable
    29 {
    30     Resource r;
    31     //通过构造方法传入资源对象的引用,从而实现让多个线程可以共享同一对象
    32     Input(Resource r){
    33         this.r=r;
    34     }
    35     public void run(){
    36         //
    37         boolean x=true;
    38         while(true){
    39                 if(x)
    40                 {
    41                     r.set("李一男","男");x=false;
    42                 }
    43                 
    44                 else
    45                 {
    46                     r.set("Alice","girl");x=true;
    47                 }
    48         }
    49     }
    50 }
    51 class Output implements Runnable
    52 {
    53     Resource r;
    54     Output(Resource r){
    55         this.r=r;
    56     }
    57     public void run(){
    58         //
    59         while(true)
    60             r.out();
    61     }
    62 }
    63 class Correspondence 
    64 {
    65     public static void main(String[] args) 
    66     {
    67         Resource r=new Resource();
    68         new Thread(new Input(r)).start();
    69         new Thread(new Output(r)).start();
    70     }
    71 }
    View Code

     生产者与消费者问题:两个生产者,两个消费者,一个共有资源

    解决方式一:利用synchronized加锁,wait()等待,notify(),notifyAll()唤醒

      不足:当多个线程时,为了避免全部等待的情况,使用notifyAll()唤醒,生产和消费都被唤醒。然而这不是所期待的,生产唤醒消费,消费唤醒生产就可以了,不必要唤醒自己人!

    Demo

     1 /**
     2 *需求;两个生产者,两个消费者,一个共享资源
     3 */
     4 //通过构造传入资源
     5 class Producer implements Runnable
     6 {
     7     Resource r;
     8     Producer(Resource r){
     9         this.r=r;
    10     }
    11     public void run(){
    12         while (true)
    13         {
    14             r.set("饲料");
    15         }
    16     }
    17 }
    18 //通过构造传入资源
    19 class Consumer implements Runnable
    20 {
    21     Resource r;
    22     Consumer(Resource r){
    23         this.r=r;
    24     }
    25     public void run(){
    26         while (true)
    27         {
    28             r.out();
    29         }
    30     }
    31 }
    32 class Resource
    33 {
    34     private String name;
    35     private int res=1;
    36     private boolean flag=false;
    37     //true则生产wait,否则生产-改true-唤醒其他所有线程
    38     public synchronized void set(String name){
    39         while(flag)
    40             try{this.wait();}catch(Exception e){}
    41         this.name=name+".."+res++;
    42         System.out.println(Thread.currentThread().getName()+"..生产资源.."+this.name);
    43         flag=true;
    44         this.notifyAll();
    45     }
    46     //false则消费wait,否则消费-改false-唤醒其他所有线程
    47     public synchronized void out(){
    48         while(!flag)
    49             try{this.wait();}catch(Exception e){}
    50         System.out.println(Thread.currentThread().getName()+"......消费资源......"+this.name);
    51         flag=false;
    52         this.notifyAll();
    53     }
    54 
    55 }
    56 class ProducerConsumer 
    57 {
    58     public static void main(String[] args) 
    59     {
    60         //创建资源
    61         Resource r=new Resource();
    62         //开启两个消费者和两个生产者线程,共享资源通过构造传入
    63         new Thread(new Producer(r),"one").start();
    64         new Thread(new Producer(r),"two").start();
    65         new Thread(new Consumer(r),"three").start();
    66         new Thread(new Consumer(r),"four").start();
    67 
    68     }
    69 }
    View Code

     Lock

    解决方式二:利用java.util.concurrent.locks这个包里面的类Lock和Condition。

    lock()-unlock()类似synchronized;condition类似加锁对象;condition.await()类似r.wait();conditon.signal(),sondition.signalAll()类似r.notify(),r.notifyAll()

      不同的是:一个锁lock可以有多个condition

    Demo

     1 /**
     2 *需求;两个生产者,两个消费者,一个共享资源
     3 */
     4 //Lock接口时定义在java.util.concurrent.locks包的
     5 import java.util.concurrent.locks.*; 
     6 class Producer implements Runnable
     7 {
     8     Resource r;
     9     Producer(Resource r){
    10         this.r=r;
    11     }
    12     public void run(){
    13         while (true)
    14         {
    15             //为何要try?因为set()throws InterruptedException
    16             try{r.set("饲料");}catch(Exception e){}
    17         }
    18     }
    19 }
    20 //通过构造传入资源
    21 class Consumer implements Runnable
    22 {
    23     Resource r;
    24     Consumer(Resource r){
    25         this.r=r;
    26     }
    27     public void run(){
    28         while (true)
    29         {
    30             
    31             try{r.out();}catch(Exception e){}
    32         }
    33     }
    34 }
    35 class Resource
    36 {
    37     private String name;
    38     private int res=1;
    39     private boolean flag=false;
    40     //注意,Lock是定义的一个接口,不能实例化的,ReentrantLock是实现了Lock的类
    41     //创建锁lock,四个线程都用这个锁
    42     Lock lock =new ReentrantLock();
    43     //创建lock的两个环境,分别是生产对象和消费对象
    44     Condition pro=lock.newCondition();
    45     Condition con=lock.newCondition();
    46     //为什么要抛?因为 void await() throw InterruptedException
    47     public void set(String name)throws InterruptedException {
    48         lock.lock();
    49         try
    50         {
    51             while(flag)
    52                 pro.await();
    53             this.name=name+".."+res++;
    54             System.out.println(Thread.currentThread().getName()+"..生产资源.."+this.name);
    55             flag=true;
    56             //只唤醒一个消费者线程!!
    57             con.signal();
    58         }
    59         finally
    60         {
    61             lock.unlock();
    62         }
    63     }
    64     //false则消费wait,否则消费-改false-唤醒其他所有线程
    65     public void out()throws InterruptedException {
    66         lock.lock();
    67         try
    68         {
    69         while(!flag)
    70             con.await();
    71         System.out.println(Thread.currentThread().getName()+"......消费资源......"+this.name);
    72         flag=false;    
    73         //只唤醒一个生产者线程
    74         pro.signal();
    75         }
    76         finally
    77         {
    78             lock.unlock();
    79         }
    80     }
    81 
    82 }
    83 class ProducerConsumer 
    84 {
    85     public static void main(String[] args) 
    86     {
    87         //创建资源
    88         Resource r=new Resource();
    89         //开启两个消费者和两个生产者线程,共享资源通过构造传入
    90         new Thread(new Producer(r),"one").start();
    91         new Thread(new Producer(r),"two").start();
    92         new Thread(new Consumer(r),"three").start();
    93         new Thread(new Consumer(r),"four").start();
    94 
    95     }
    96 }
    View Code

    注意:

    1.Lock:在java.util.concurrent.locks包中,是一个接口,ReentrantLock是一个实现了该接口的一个类

      所以创建锁时  Lock lock=new ReentrantLock();是合法的

    2.使用锁

        ... method()throws InterruptedException {//调用时还得处理异常
            lock.lock();//锁开始
            try
            {
                ...
                conditiona.await();//就是这玩意儿抛异常
                            ...
                conditionb.signal();
            }
            finally//必须的,不然发生异常时,就不能解锁了
            {
                lock.unlock();//锁结束
            }
        }

     中断public void interrupt()

     情景:假设总共有主线程和一个子线程在执行,子线程冻结了(wait ,await),主线程执行完了且未唤醒子线程,此时整个程序就停下来了,且不会结束子线程,因为子线程的run()方法没有执行完成!!

     interrupt():清除线程的冻结状态

     1 /**
     2 *需求:
     3 *一个主线程,一个子线程,让主线程执行完且子线程冻结
     4 *尝试用interrupt()清除子线程的冻结状态
     5 */
     6 class InterruptDemo 
     7 {
     8     public static void main(String[] args) 
     9     {
    10         int count=100;
    11         Interrupt in=new Interrupt();
    12         Thread t=new Thread(in,"child");
    13         t.start();
    14         while(count>0){
    15             System.out.println(Thread.currentThread().getName()+"..."+count--);
    16         }
    17         System.out.println("man is over");
    18         in.changeFlag();
    19         //清除冻结状态
    20         //t.interrupt();
    21     }
    22 }
    23 class Interrupt implements Runnable
    24 {
    25     private boolean flag=true;
    26     public synchronized void run(){
    27         while (flag)
    28         {
    29             try
    30             {
    31                 this.wait();
    32             }
    33             catch (Exception e)
    34             {
    35                 System.out.println(Thread.currentThread().getName()+"..."+"Exception");
    36             }
    37             System.out.println(Thread.currentThread().getName()+"..."+"run");
    38         }
    39     }
    40     public void changeFlag(){
    41         flag=false;
    42     }
    43 }
    View Code

    public final void join() throws InterruptedException

    作用:抢夺(主线程?)执行权,让主线程等待join进来的线程执行完毕。

    待解决:何时抛出中断异常

     1 //join  强制抢夺执行权,所以可能异常
     2 /**
     3 *主线程和一个子线程执行,加入第二个子线程,夺取正在执行的线程的执行权
     4 */
     5 class JoinDemo 
     6 {
     7     public static void main(String[] args) throws InterruptedException
     8     {
     9         int num=100;
    10         Join j=new Join();
    11         //注意,线程t1和t2均传入j,这样就共同操作j这个对象了---线程通信
    12         Thread t1=new Thread(j,".....one");
    13         Thread t2=new Thread(j,"two");
    14         t1.start();//t1线程开启
    15         t1.join();//此时是main在执行t1.join,main要等到t1完成才会继续执行
    16         t2.start();//t1执行完了,t2才开启
    17 
    18 
    19         while(num>0)
    20             System.out.println("main........."+num--);
    21         System.out.println("over");
    22     }
    23 }
    24 class Join implements Runnable
    25 {
    26     private int num=100;
    27     public synchronized void run(){
    28     while(num>0)
    29         System.out.println(Thread.currentThread().getName()+"..."+num--);
    30     System.out.println(Thread.currentThread().getName()+".........is..........over");
    31     }
    32 }
    View Code

    守护线程(后台线程)public final void setDaemon(boolean on)

    ?:线程可分为前台线程和后台线程,当所有前台线程都结束后,剩下的后台线程立刻停止,程序结束。

    注意:将线程设置成守护线程,要在线程开启之前。且要慎用!

     1 /**
     2 *测试:两个守护子线程等待,主线程执行完毕,程序时候结束
     3 */
     4 class DaemonDemo 
     5 {
     6     public static void main(String[] args) 
     7     {
     8 
     9         Daemon d1=new Daemon();
    10         Thread t1=new Thread(d1,"one");
    11         Thread t2=new Thread(d1,"two");
    12         int num=60;
    13         //在启动之前设置守护线程,守护线程就是后台线程
    14         //当所有的前台线程执行完时,剩余的后台线程将会停止
    15         t1.setDaemon(true);
    16         t2.setDaemon(true);
    17         t1.start();
    18         t2.start();
    19         while(true){
    20             if(num==0){
    21                 System.out.println("man is over");
    22                 break;
    23             }
    24             System.out.println("main......"+num--);
    25         }
    26         
    27     }
    28 }
    29 class Daemon implements Runnable
    30 {
    31 
    32     private boolean flag=true;
    33     //不加synchronized会抛出异常
    34     public synchronized void run(){
    35         while(flag)
    36         try
    37         {
    38             this.wait();
    39         }
    40         catch (InterruptedException e)
    41         {
    42             System.out.println("wait fof exception");
    43         }
    44     }
    45 }
    View Code

    线程优先级(1,5,10)与匿名内部类开启线程

     1 /**
     2 需求:查看和设置线程的优先级 toString setPriority
     3 需求:yield让线程暂时释放执行权
     4 需求:使用两种匿名内部类的方式开启线程
     5 //问题:在使用Thread匿名内部类的时候,如何给线程命名?->I get it!
     6 */
     7 class  ThreadDemo
     8 {
     9     public static void main(String[] args) 
    10     {
    11         //Thread匿名内部类
    12         new Thread("one"){
    13             public void run(){
    14                 for(int i=0;i<50;i++){
    15                     System.out.println(this.toString()+"...."+i);
    16                     //释放
    17                     Thread.yield();
    18                 }
    19             }
    20         }.start();
    21         //Runnable匿名内部类
    22         Runnable r=new Runnable(){
    23             public void run(){
    24                 for(int i=0;i<50;i++){
    25                     //这里不能用this,否则调用的是Object原始的toString
    26                     System.out.println(Thread.currentThread().toString()+"...."+i);
    27                     //释放
    28                     Thread.yield();
    29                 }
    30             }
    31         };
    32         new Thread(r,"two").start();
    33         //优先级1,5,10,学着:public static final int MAX_PRIORITY=10;用静态定义常量
    34         Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
    35         for(int i=0;i<50;i++){
    36             //这里不能用this,否则调用的是Object原始的toString
    37             System.out.println(Thread.currentThread().toString()+"...."+i);
    38         }
    39     }
    40 }
    
    
  • 相关阅读:
    cocos2d-x笔记5: 通过jni实现C++调用Java
    cocos2d-x笔记4: TextField不能删除内容,以及我的解决办法。。。
    C++ 11 笔记 (六) : 随机数
    C++ 11 笔记 (五) : std::thread
    C++ 11 笔记 (四) : std::bind
    C++ 11 笔记 (三) : auto
    C++ 11 笔记 (二) : for循环
    要做的题目
    【C补充】结构体的内存分配,匈牙利命名法
    【C补充】文件操作
  • 原文地址:https://www.cnblogs.com/erhai/p/4702147.html
Copyright © 2011-2022 走看看