继承Thread和实现Ruunable接口的区别
1.首先继承Thread是父类与子类的关系,实现Ruunable接口是实现类和接口的关系。
2.继承只能单继承,而接口可以多实现。(先继承后实现。)
3.如果一个类继承Thread,则不适合资源共享(成员变量加上static修饰也可以实现资源共享),但是实现了Runnable接口的话,则容易实现资源共享。
4.实现Runnable接口,增加程序的健壮性。代码可以被多个线程共享,代码和属性共享
继承Thread和实现Ruunable接口的特点
1. 继续Thread类。重写run方法。测试类时,创建多个线程,加上static修饰成员变量表示数据共享就是共同完成一个任务()。
2.实现Runnable接口,重写run方法,并且将Runnable子类对象作为参数,传入Thread对象
创建一个实现类对象实现runnable接口,测试类时,只用创建一个实现类对象,可以创建多个线程共同完成任务,(不用static修饰成员变量)
继承Thread类
// 继承Thread类
public class BeanThread extends Thread {
// 1.声明一个成员变量用被每一个线程对象共享static修饰,
private static int bean = 100;
/**
* 2. 同步方法(重点掌握)
用synchronized关键字修饰方法即可,在修饰符位置,返回值前面
如果方法是static修饰的:同步的是 :当前类.class
如果方法是非static修饰的:同步的是: this
如果继承Thread的方式,同步方法的话,就需要将方法改为static修饰,所以说,一般我们不用同步方法
一般建议继承Thread用同步代码块或者锁机制
*/
// 声明一个robBean方法表示抢豆子功能
private static synchronized void robBean() {// 同步方法,如果方法是类方法,则同步对象默认是:当前类.class
//private synchronized void robBean() {//同步方法,如果方法是实例方法,则同步对象默认是:this
Thread ct = Thread.currentThread();// 获取当前线程对象
String name2 = ct.getName();// 获取当前线程对象名
if (bean > 0) {
System.out.println(name2+":抢到豆子:" + bean);
bean--;
}
}
/**
* 构造方法
* 无参构造方法和带参构造方法
*/
public BeanThread() {
super();
}
public BeanThread(String name) {
super(name);
}
/**
* 重写run方法,方法中用while循环调用robBean方法
*/
@Override
public void run() {
while (bean > 0) {
// 调用抢豆子方法robBean
robBean();
}
}
}
线程测试类
/**
* 线程测试类
* 测试抢豆子线程BeanThread
* 测试方式:
* 创建5个BeanThread对象,传入线程名
* 调用start方法启动线程
*/
public class BeanThreadTest {
public static void main(String[] args) {
/** 创建5个线程BeanThread对象表示窗口 */
BeanThread t1 = new BeanThread("豆子1");
BeanThread t2 = new BeanThread("豆子2");
BeanThread t3 = new BeanThread("豆子3");
BeanThread t4 = new BeanThread("豆子4");
BeanThread t5 = new BeanThread("豆子5");
//调用start方法启动线程
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
实现Runnable接口
/**
* 创建启动线程的方法二:Runnable方法
*/
public class BeanImpl implements Runnable{
/**
* 声明一个static修饰的成员变量被每个线程共享
*/
// private static int bean = 100;
private static int bean = 100;
// 成员变量
String name;
/**
* 构造方法
* 定义一个带参构造方法
*/
public BeanImpl(String name) {
this.name = name;
}
public BeanImpl() {
// TODO Auto-generated constructor stub
}
/**
* 定义一个方法实现卖票功能
*/
private static synchronized void sellbean() {
/*//获取当前线程对象,谁调用就是谁的线程
Thread currentThread = Thread.currentThread();
//获取线程对象的名字
String name = currentThread.getName();*/
/**
* 不加if判断,线程1买最后一张票,线程2和线程3也进来了,
* 在外面等待,但是他们不知道线程1卖的最后一张,就会去执行买票功能
* 再加一个if判断,从而线程2,3进来过后发现票没了就不会进行卖票了
*/
if (bean>0) {
System.out.println(Thread.currentThread().getName()+"豆子;"+bean);
bean--; // 每执行一次票数就减1
}
}
/* *//**
* 重写run方法,当启动线程时,默认会执行run方法
*
*//*
*/ @Override
public void run() {
//需要再加一个条件if票大于0
//注意同步代码快不能加在这里,不然加在这里过后一个线程会一直执行
while (bean>0) { //当票大于0就一直卖
sellbean();
}
}
}
实现Runnable接口测试类
/**
* 线程测试类
* 测试线程BeanImpl
* 测试方式:
* 创建1个BeanImpl对象,传入线程名
* 调用start方法启动线程
*/
public class BeanImplTest {
public static void main(String[] args) {
/** 创建1个线程BeanImpl对象 */
BeanImpl t1 = new BeanImpl();
/**
* 因为Runnable接口没有start方法
* 需要创建线程对象将参数Runnable实现类对象传进去
*/
Thread t11 = new Thread(t1,"豆12");
Thread t22 = new Thread(t1,"豆23");
Thread t33 = new Thread(t1,"豆23");
Thread t44 = new Thread(t1,"豆45");
Thread t55 = new Thread(t1,"豆56");
//调用start方法启动线程
t11.start();
t22.start();
t33.start();
t44.start();
t55.start();
}
}