一.继承Thread类:
步骤如下:
(1)创建线程类,写一个子类(Mythread)继承Thread类
(2)在子类(Mythread)中重写run方法,run方法中是线程的主体代码块
(3)在主函数中创建子类(Mythrerad)的实例对象(t1)
(4)通过实例对象(t1)调用start方法启动线程( t1.start() )
代码如下:
(1)Mythreaad 类(线程类)
public class Mythread extends Thread{
//该线程为循环打印
public void run() {
for (int i=1;i<5;i++){
//geName() 为获取当前线程的名字,用于分辨是哪个线程在执行
System.out.println( getName() + "正在打印第 "+i +"次" );
}
}
}
(2)Demothread 类 (主函数)
public class Demothread01 {
public static void main(String[] args) {
//创建线程对象
Mythread t1 = new Mythread();
Mythread t2 = new Mythread();
//对线程进行命名
t1.setName("线程一");
t2.setName("线程二");
//启动线程
t1.start();
t2.start();
}
}
(3)运行结果如下
线程二正在打印第 1次
线程二正在打印第 2次
线程一正在打印第 1次
线程二正在打印第 3次
线程一正在打印第 2次
线程一正在打印第 3次
线程二正在打印第 4次
线程一正在打印第 4次
线程二正在打印第 5次
线程一正在打印第 5次
二.实现Runnable接口:
步骤如下:
(1)创建线程类,写一个类(Mythread)实现 Runnable接口
(2)在该类(Mythread)中重写 run 方法
(3)在主函数中创建该类(Mythread)的实例(mt) //mt也可叫线程实例对象
(4)创建Thread类的实例(t1),并将线程对象(mt)作为参数传入 //为线程实例对象创建线程
(5)调用线程(t1)的start方法启动线程
代码如下:
(1)Mythread 类 (线程类)
public class Mythread implements Runnable{
//run 方法为循环打印
public void run() {
//getName()是Thread的方法 所以先通过Thread.currentThread()获取当前线程,再使用getName获取名字
String Threadname=Thread.currentThread().getName(); //获取当前线程的名字
for(int i=1; i<=4 ; i++){
System.out.println(Threadname+ "正在打印第 "+i +"次" );
}
}
}
(2)Demothread 类(主函数)
public class DemoThread02 {
public static void main(String[] args) {
//创建线程对象
Mythread mt =new Mythread();
//为线程对象创建两个线程
Thread t1 = new Thread(mt);
Thread t2 = new Thread(mt);
//为线程命名
t1.setName("线程一");
t2.setName("线程二");
//启动线程
t1.start();
t2.start();
}
}
(3)运行结果如下
线程二正在打印第 1次
线程二正在打印第 2次
线程一正在打印第 1次
线程一正在打印第 2次
线程二正在打印第 3次
线程一正在打印第 3次
线程二正在打印第 4次
线程一正在打印第 4次
三.实现Callable的接口:
步骤如下:
(1)创建线程类,写一个类(Mythread)实现 Callable接口
(2)在该类(Mythread)中重写 call 方法
(3)在主函数中创建该类(Mythread)的实例(mt)
(4)创建FutureTask 实例(ft)用于管理线程运行结果
(5)创建Threead的实例(t1)并将FutureTask的实例(ft)传入
(6)调用线程(t1)的start方法启动线程
代码如下:
(1)Mythread 类 (线程类)
public class Mythread implements Callable <Integer> {
int max=0;
public Integer call() throws Exception{
//获取线程对象,以操作线程
String name = Thread.currentThread().getName();
System.out.println(name+"启动"); //查看线程状态
for(int i=0; i<50; i++){
max+=i;
}
System.out.println(name+"关闭");
return max; //执行完线程后返回一个值
}
}
(2)Demothread 类 (主函数)
public class DemoThread03 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程对象实例
Mythread mt1 = new Mythread();
Mythread mt2 = new Mythread();
//创建FutureTask实例对象管理多线程运行的结果
FutureTask<Integer> ft1 =new FutureTask<>(mt1);
FutureTask<Integer> ft2 =new FutureTask<>(mt2);
//为两个对象创建两个线程
Thread t1 = new Thread(ft1);
Thread t2 = new Thread(ft2);
//对线程进行命名
t1.setName("线程一");
t2.setName("线程二");
//启动线程
t1.start();
t2.start();
//FutureTAsk(实例).get获取线程返回的信息并打印
System.out.println(t1.getName()+"返回"+ft1.get());
System.out.println(t2.getName()+"返回"+ft2.get());
}
}
(3)运行结果如下
线程一启动
线程二启动
线程二关闭
线程一关闭
线程一返回1225
线程二返回1225
四.不同方法的特点与分析
(1)继承Thread类
该方法简单明了,特点是创建多个线程时必须创建多个线程对象与之对应,空间上开销略大,并且由于是一个对象对应一个线程,在一些数据的共享或对同一类的多线程操作中会存在一些问题。如需要将数据修饰为static才能对共享数据进行操作。还有就是,java中只支持单继承.在继承完Thread后就不能再继承其它类,对以后该线程功能的添加有影响。
(2)实现Runnable接口
该方法相对于继承Tread要复杂一点,由于Java是支持多个接口的实现的所以不会出现继承的局限性,并且由于一个对象可以创建多个线,这就自动实现了数据的共享,更适合处理有共享数据的业务逻辑。
(3)实现Callable接口
该方法与第二种(实现Runnable 接口)相似但相对于前两种更为复杂,该方法的优点是可以获取 run 方法的返回值来了解线程的状态,不过对于线程较少时该功能也可通过将数据修饰为static来实现。
五.总结
在实际运用中要根据不同方法的特点来进行选择,如此才能避免事倍功半。