线程的两种实现方式,以及区别

-  让类成为线程类有两种方式,实现Runnable接口,以及继承Thread类(类中实现了Runnable接口,还提供了一些额外的方法)。 

一、Runnable相对优势:

  • java的单继承,当继承了Thread类,则不能继承其他类,而实现Runnable接口可以

  • 实现Runnable接口的线程类的多个线程,可以访问同一变量,而Thread则不能(多窗口买票问题)

原因:两种方式启动方式不同:

 

  • Runnable线程类是实例化一个对象o之后,通过多次new Thread(o).start();启动多个线程,而这几个线程属于一个对象,对象的成员变量是同一个。
  • Thread线程类启动多个线程需要 new MyThread().start();每个线程启动都对应多个对象,他们的成员变量是独立的。

 测试代码如下:

(1)实现Runnable:

 1 package com.loan.entity;
 2  
 3 import lombok.Data;
 4  
 5 @Data
 6 public class Test2 implements Runnable{
 7 private int ticket=100;
 8 @Override
 9 public void run() {
10     // TODO Auto-generated method stub
11     while(true){
12         if(ticket>0){
13             System.out.println(Thread.currentThread().getName()+"...is saling,余票:"+ticket--);
14         }
15     }
16 }
17 public static void main(String[] args) {
18     Test2 t=new Test2();//只能使用同一个t
19     new Thread(t).start();
20     new Thread(t).start();
21     new Thread(t).start();
22     new Thread(t).start();
23 }
24 }

 

运行结果:

(2)继承Thread

 1 package com.loan.entity;
 2  
 3 public class Test3 extends Thread{
 4     int ticket=100;
 5     public void run(){
 6         while(true){
 7             if(ticket>0){
 8                 System.out.println(Thread.currentThread().getName()+"...is saling,余票:"+ticket--);
 9             }
10         }
11     }
12     public static void main(String[] args) {
13         new Test3().start();
14         new Test3().start();
15         new Test3().start();
16         new Test3().start();
17     }
18 }

很明显,上面这种方式是错误的!

继承Thread类也可以通过内部类发方式实现。代码如下:

 1 package com.loan.entity;
 2  
 3 public class Test3{
 4     private  int ticket=100;
 5     class InnerClass extends Thread{
 6         private Test3 t3;
 7         InnerClass(Test3 t){
 8             t3=t;
 9         }
10         public void run(){
11             while(true){
12                 if(ticket>0){
13                     ticket--;
14                     System.out.println(Thread.currentThread().getName()+"...is saling,余票:"+ticket);
15                 }
16             }
17         }
18     }
19     public static void main(String[] args) {
20         Test3 test3=new Test3();
21         Thread t1=test3.new InnerClass(test3);
22         Thread t2=test3.new InnerClass(test3);
23         Thread t3=test3.new InnerClass(test3);
24         Thread t4=test3.new InnerClass(test3);
25         t1.setName("t1");
26         t2.setName("t2");
27         t3.setName("t3");
28         t4.setName("t4");
29         t1.start();
30         t2.start();
31         t3.start();
32         t4.start();
33         }
34 }

 

运行结果:

二、Thread优势

1、使用线程的方法方便一些,例如:获取线程的Id(Thread.currentThread().getId())、线程名(Thread.currentThread().getName())、线程状态(Thread.currentThread().getState())等

2、操作同一变量,但是线程调用run方法内容不同时,使用Thread内部类的方式进行,例如生产者、消费者模式

生产者消费者多线程例子:

 1 package com.loan.entity;
 2  
 3 public class Store {
 4     private final int MAX_SIZE=2;//仓库总共可存放货物
 5     private int count=0;//当前仓库货物
 6     public synchronized void add() throws InterruptedException{
 7         while(count>=MAX_SIZE){
 8             System.out.println("仓库已满");
 9             System.out.println(Thread.currentThread().getName()+"等待中。。。。");
10             this.wait();
11         }
12             count++;
13             System.out.println(Thread.currentThread().getName()+"存入仓库,当前货物数:"+count);
14             this.notify();
15     }
16     public synchronized void remove() throws InterruptedException{
17         while(count<=0){
18             System.out.println("仓库空了");
19             System.out.println(Thread.currentThread().getName()+"等待中。。。。");
20             this.wait();
21         }
22             count--;
23             System.out.println(Thread.currentThread().getName()+"取出货物,当前货物数:"+count);
24             this.notify();
25     }
26     public static void main(String[] args) {
27         Store s=new Store();
28         Thread producer1=s.new Producer(s);//成员内部类需通过对象访问
29         Thread producer2=s.new Producer(s);
30         Thread consumer1=s.new Consumer(s);
31         Thread consumer2=s.new Consumer(s);
32         producer1.setName("producer1");//利用Thread中的方法
33         producer2.setName("producer2");
34         consumer1.setName("consumer1");
35         consumer2.setName("consumer2");
36         producer1.start();
37         producer2.start();
38         consumer1.start();
39         consumer2.start();
40     }
41     class Producer extends Thread{
42         private Store store;
43         Producer(Store s){
44             store=s;
45         }
46         public void run(){
47             while(true){
48                 try {
49                     store.add();
50                     Thread.sleep(10000);
51                 } catch (InterruptedException e) {
52                     // TODO Auto-generated catch block
53                     e.printStackTrace();
54                 }
55             }
56         }
57     }
58     class Consumer extends Thread{
59         private Store store;
60         Consumer(Store s){
61             store=s;
62         }
63         public void run(){
64             while(true){
65                 try {
66                     store.remove();
67                     Thread.sleep(15000);
68                 } catch (InterruptedException e) {
69                     // TODO Auto-generated catch block
70                     e.printStackTrace();
71                 }
72             }
73         }
74     }
75 }

 

运行结果:

 

 

 

 

 

 

   

posted @ 2018-08-09 17:33  一辈子de赌注  阅读(5969)  评论(0编辑  收藏  举报