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

来源:互联网 发布:linux 驱动 usleep 编辑:程序博客网 时间:2024/05/16 13:50

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

一、Runnable相对优势:

1、java的单继承,当继承了Thread类,则不能继承其他类,而实现Runnable接口可以
2、实现Runnable接口的线程类的多个线程,可以访问同一变量,而Thread则不能(多窗口买票问题)

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

Runnable线程类是实例化一个对象o之后,通过多次new Thread(o).start();启动多个线程,而这几个线程属于一个对象,对象的成员变量是同一个。

Thread线程类启动多个线程需要 new MyThread().start();每个线程启动都对应多个对象,他们的成员变量是独立的。

测试代码如下:

(1)实现Runnable:

package com.loan.entity;import lombok.Data;@Datapublic class Test2 implements Runnable{private int ticket=100;@Overridepublic void run() {// TODO Auto-generated method stubwhile(true){if(ticket>0){System.out.println(Thread.currentThread().getName()+"...is saling,余票:"+ticket--);}}}public static void main(String[] args) {Test2 t=new Test2();//只能使用同一个tnew Thread(t).start();new Thread(t).start();new Thread(t).start();new Thread(t).start();}}
运行结果:



(2)继承Thread

package com.loan.entity;public class Test3 extends Thread{int ticket=100;public void run(){while(true){if(ticket>0){System.out.println(Thread.currentThread().getName()+"...is saling,余票:"+ticket--);}}}public static void main(String[] args) {new Test3().start();new Test3().start();new Test3().start();new Test3().start();}}
运行结果:


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

继承Thread类也可以通过内部类发方式实现。代码如下:
package com.loan.entity;public class Test3{private  int ticket=100;class InnerClass extends Thread{private Test3 t3;InnerClass(Test3 t){t3=t;}public void run(){while(true){if(ticket>0){ticket--;System.out.println(Thread.currentThread().getName()+"...is saling,余票:"+ticket);}}}}public static void main(String[] args) {Test3 test3=new Test3();Thread t1=test3.new InnerClass(test3);Thread t2=test3.new InnerClass(test3);Thread t3=test3.new InnerClass(test3);Thread t4=test3.new InnerClass(test3);t1.setName("t1");t2.setName("t2");t3.setName("t3");t4.setName("t4");t1.start();t2.start();t3.start();t4.start();}}

运行结果:


二、Thread优势

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

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

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

package com.loan.entity;public class Store {private final int MAX_SIZE=2;//仓库总共可存放货物private int count=0;//当前仓库货物public synchronized void add() throws InterruptedException{while(count>=MAX_SIZE){System.out.println("仓库已满");System.out.println(Thread.currentThread().getName()+"等待中。。。。");this.wait();}count++;System.out.println(Thread.currentThread().getName()+"存入仓库,当前货物数:"+count);this.notify();}public synchronized void remove() throws InterruptedException{while(count<=0){System.out.println("仓库空了");System.out.println(Thread.currentThread().getName()+"等待中。。。。");this.wait();}count--;System.out.println(Thread.currentThread().getName()+"取出货物,当前货物数:"+count);this.notify();}public static void main(String[] args) {Store s=new Store();Thread producer1=s.new Producer(s);//成员内部类需通过对象访问Thread producer2=s.new Producer(s);Thread consumer1=s.new Consumer(s);Thread consumer2=s.new Consumer(s);producer1.setName("producer1");//利用Thread中的方法producer2.setName("producer2");consumer1.setName("consumer1");consumer2.setName("consumer2");producer1.start();producer2.start();consumer1.start();consumer2.start();}class Producer extends Thread{private Store store;Producer(Store s){store=s;}public void run(){while(true){try {store.add();Thread.sleep(10000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}class Consumer extends Thread{private Store store;Consumer(Store s){store=s;}public void run(){while(true){try {store.remove();Thread.sleep(15000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}

运行结果:

阅读全文
0 0
原创粉丝点击