java自定义线程类继承Thread与实现Runnale的区别
实例: 继承Thread线程类
public class MyThread extends Thread{
@Override
public void run(){
System.out.println("这是自定义线程类继承Thread");
}
}
实例: 实现 Runnable接口
public class MyThread implements Runnable{
@Override
public void run(){
System.out.println("自定义线程类实现Runnable接口");
}
}
区别:
1) 创建对象的方式不同
a. 继承Thread的类创建对象
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
MyThread mt3 = new MyThread();
b. 实现Runnable接口的类创建对象
MyThread mt = new MyThread();
Thread t1 = new Thread(mt);
Thread t2 = new Thread(mt);
Thread t3 = new Thread(mt);
2) 如果自定义类中需要使用成员变量, 继承类每创建一个对象, 成员变量就是独立的, 当需要多线程同时访问该成员变量的时候, 成员变量就会变成多个, 就会出现线程安全问题, 所以就需要用 static 修饰成员变量, 而实现接口的类, 需要创建对象, 并将的对象作为参数传递给Thread创建线程对象, 才能独立启动线程 , 根据源码, 线程会去执行自定义类的run()方法, 多线程访问时, 访问的是同一个对象的成员变量, run()方法, 所以成员变量不需要用static修饰
所以当多线程同时访问时, 继承Thread的类的成员变量必须用 static 修饰, 实现接口的类就可以不用 static 修饰
3) 线程同步, 同步方法的时候
a. 如果方法被 static 修饰, 那么方法所在类的字节码对象就是同步监听对象
b. 方法没有 static 修饰, 那么 this(当前访问线程对象)就是同步监听对象, 如果自定义线程类采用的是继 承Thread类, 那么同步方法时必须用 static 修饰, 每创建一个线程对象, 就要 new 一次, this 指代的 就是不同的对象, 达不到同步的效果, 自定义类采用实现接口声明的, 同步方法就可以不用 static 修饰, 因为通过该方式创建的线程, 访问的对象只有一个, 所以 this 是不变的
4) 线程同步, 使用锁机制时
a. 当自定义类是通过继承声明的, 那么锁必须是static修饰的成员变量
b. 自定义类是通过实现接口声明的时, 锁对象不需要static修饰