1、继承Thread类,覆盖定义run方法
class A1 extends Thread{
@Override
public void run() {
for(int i=0;i<50;i++){
System.out.println("左手一个慢动作... ...");
try {
this.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//创建线程对象 Thread t1=new A1(); //启动线程 t1.start();
优点:可以直接使用Thread类中的方法this.sleep(1000)
,代码简单
缺点:继承Thread类之后就不能继承其他的类,Java的单根继承体系
2、实现Runnable接口,定义run方法
class A2 implements Runnable{
@Override
public void run() {
for(int i=0;i<50;i++){
System.out.println("后手慢动作重播......");
//获取执行程序的线程对象
Thread t1=Thread.currentThread();
try {
t1.sleep(900);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//创建线程对象 Thread t1=new Thread(new A2()); //启动线程,执行A2的run方法 t1.start();
优点:即使自定义类已经有父类了也不受影响,因为可以实现多个接口
缺点:在run方法内部需要获取到当前线程的Thread对象后才能使用Thread中的方法
实现run方法时没有返回值,所以需要获取线程的执行结果需要自行编程实现
public class A3 implements Runnable {
private int begin,end;
private int result;
public A3(int begin,int end){
this.begin=begin;
this.end=end;
}
public void run(){
for(int i=begin;i<=end;i++){
result+=i;
}
}
public int getResult(){
return this.result;
}
}
3、实现Callable接口和Future接口的方法
class A3 implements Callable { // <>叫做泛型,可以理解为类型参数
private int begin,end;
public A3(int begin,int end){
this.begin=begin;
this.end=end;
}
@Override
public Object call() throws Exception {
int res=0;
for(int i=begin;i<=end;i++)
res+=i;
return res;
}
}
//创建并启动线程对象 //Java针对Future和Runnable接口提供了一个实现类FutureTask Callable c=new A3(); FutureTask ft=new FutureTask(c); Thread t=new Thread(ft); t.start(); //如何获取线程的执行结果 Object res=ft.get(); //会阻塞当前执行线程,并等待子线程执行完成后获取返回值
优点:可以获取返回值,可以抛出异常
缺点:代码编写较为复杂
4、使用线程池
优点:大大减少对象的创建,降低系统内存的使用,以提高程序的执行效率。
缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。