多线程

第一种创建方式:继承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 }

原文地址:https://www.cnblogs.com/erhai/p/4702147.html