一:继承Thread类
1:重写run()方法
2:创建类对象并调用start()方法,即可启用多线程
通过继承Thread类的类,实例化一个类对象,再通过这个(子)类对象调用Thread类(父)中的start方法.
package thread;
/**
* 开启多线程的方法一----继承Thread类:
* 1:重写run()方法
* 2:创建类对象并调用start()方法,即可启用多线程
*
*/
public class Demo01 extends Thread
{
public void run()
{
super.run();//run方法线程体
for(int i= 0;i<20;i++)
{
System.out.println("线程1----"+i);
}
}
public static void main(String[] args)
{
//因为CPU处理速度过快,i设置大时才能看出这是多线程并发执行
//线程也不一定立刻执行,而是由CPU调度决定处理的顺序,但一定是并发执行
Demo01 demo01 = new Demo01();
/**
* 通过继承Thread类的类,实例化一个类对象,再通过这个(子)类对象调用Thread类(父)中的start方法,
* 本质是一个回调函数,由 start方法新创建的线程会调用这个方法从而执行需要的代码
*/
demo01.start();
//main方法线程体
for(int i=500;i>0;i--)
{
System.out.println("线程2----"+i);
}
}
}
二:实现Runnable接口
1:通过继承Runnable接口类实现对象,
2:因为Thread类中实例化对象的语句需要传入一个Runnable类型的参数,便把实现了Runnable接口的类对象作为参数传入
3:再通过Thread类的实例化对象 thread,调用start方法
package thread;
//实现Runnable接口
public class Demo03 implements Runnable
{
public static void main(String[] args)
{
//创建Runnnable接口的类实现对象
Demo03 demo03 = new Demo03();
//创建线程对象,通过线程对象开启线程,称之为代理
Thread thread = new Thread(demo03);
/**
* 通过继承Runnable接口类实现对象,
* 因为Thread类中实例化对象的语句需要传入一个Runnable类型的参数,便把实现了Runnable接口的类对象作为参数传入
* 再通过Thread类的实例化对象 thread,调用start方法
*
* 上下两个语句还可合并为 new Thread(demo03).start();
*
* 两种开启多线程的方法相似的原因是因为Thread类是实现了Runnable接口的类,所以本质上没有区别,
* 只是因为在Java中,接口多继承而类只能单继承的特点,更推荐使用实现Runnable接口的方法开启多线程
*
* */
new Thread(demo03).start();
thread.start();
//main方法线程体
for(int i=500;i>0;i--)
{
System.out.println("线程2----"+i);
}
}
@Override
public void run()
{
for(int i= 0;i<20;i++)
{
System.out.println("线程1----"+i);
}
}
}
ps:两种开启多线程的方法相似的原因是因为Thread类是实现了Runnable接口的类,所以本质上没有区别,只是因为在Java中,接口多继承而类只能单继承的特点,更推荐使用实现Runnable接口的方法开启多线程
三:实现Callable接口
实现Callable接口,创建执行服务,开辟线程空间,执行后关闭线程空间
package thread;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.commons.io.FileUtils;
/*
* //Callable就是产生线程池的接口
//可以定义返回值
//可以抛出异常
* 了解即可
*
* */
public class Demo05 implements Callable<Boolean>
{
private String url;
private String name;
public Demo05(String url,String name)
{
this.name=name;
this.url=url;
}
public static void main(String[] args) throws InterruptedException, ExecutionException
{
Demo05 t1 = new Demo05("https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=d&word=KameRider&step_word=&hs=0&pn=5&spn=0&di=7060663421280190465&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&istype=2&ie=utf-8&oe=utf-8&in=&cl=2&lm=-1&st=-1&cs=475209920%2C974142725&os=1851668971%2C4069697802&simid=475209920%2C974142725&adpicid=0&lpn=0&ln=275&fr=&fmq=1649684591285_R&fm=result&ic=&s=undefined&hd=&latest=©right=&se=&sme=&tab=0&width=&height=&face=undefined&ist=&jit=&cg=&bdtype=0&oriquery=&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%3A%2F%2Fhbimg.b0.upaiyun.com%2F107790b1f8aaafd68156c85b410f20b6954f7cf64678e-HCGZy5_fw236%26refer%3Dhttp%3A%2F%2Fhbimg.b0.upaiyun.com%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1652276600%26t%3Dcc3df812cee7fc6d65243255a4b98919&fromurl=ippr_z2C%24qAzdH3FAzdH3Fi7wkwg_z%26e3Bv54AzdH3Fk5w61fAzdH3F90bmlcc9AzdH3F&gsm=6&rpstart=0&rpnum=0&islist=&querylist=&nojc=undefined&dyTabStr=MCw0LDUsMSw2LDMsNyw4LDIsOQ%3D%3D","Kuuga");
Demo05 t2 = new Demo05("https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=d&word=KameRider&step_word=&hs=0&pn=6&spn=0&di=7060663421280190465&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&istype=2&ie=utf-8&oe=utf-8&in=&cl=2&lm=-1&st=-1&cs=2838076070%2C369928604&os=1639080999%2C1502824316&simid=2838076070%2C369928604&adpicid=0&lpn=0&ln=275&fr=&fmq=1649684591285_R&fm=result&ic=&s=undefined&hd=&latest=©right=&se=&sme=&tab=0&width=&height=&face=undefined&ist=&jit=&cg=&bdtype=0&oriquery=&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%3A%2F%2Fhbimg.b0.upaiyun.com%2F9361d0141ebf125ea6b83a77f9baa917aa61c59454d2b-qgT3Lw_fw236%26refer%3Dhttp%3A%2F%2Fhbimg.b0.upaiyun.com%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1652276600%26t%3Dc5568c850e52143d4d95725455631aef&fromurl=ippr_z2C%24qAzdH3FAzdH3Fi7wkwg_z%26e3Bv54AzdH3Fk5w61fAzdH3F90bmlcc9AzdH3F&gsm=6&rpstart=0&rpnum=0&islist=&querylist=&nojc=undefined&dyTabStr=MCw0LDUsMSw2LDMsNyw4LDIsOQ%3D%3D","Blade");
Demo05 t3 = new Demo05("https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=d&word=KameRider&step_word=&hs=0&pn=7&spn=0&di=7060663421280190465&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&istype=2&ie=utf-8&oe=utf-8&in=&cl=2&lm=-1&st=-1&cs=2865016088%2C351628382&os=1583059613%2C1136490781&simid=3433901838%2C126903493&adpicid=0&lpn=0&ln=275&fr=&fmq=1649684591285_R&fm=result&ic=&s=undefined&hd=&latest=©right=&se=&sme=&tab=0&width=&height=&face=undefined&ist=&jit=&cg=&bdtype=0&oriquery=&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%3A%2F%2Fhbimg.b0.upaiyun.com%2F6030ee7e1733a6d6a44f5ef88e56d85ff916c4a05bef2-TvCK7W_fw236%26refer%3Dhttp%3A%2F%2Fhbimg.b0.upaiyun.com%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1652276600%26t%3Def967fc1b9798e6a90abf0d45c0a0c31&fromurl=ippr_z2C%24qAzdH3FAzdH3Fi7wkwg_z%26e3Bv54AzdH3Fk5w61fAzdH3F90bmlcc9AzdH3F&gsm=6&rpstart=0&rpnum=0&islist=&querylist=&nojc=undefined&dyTabStr=MCw0LDUsMSw2LDMsNyw4LDIsOQ%3D%3D","Gaim");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);//三个线程,则需要开辟三个空间
//提交执行
Future<Boolean> result1=ser.submit(t1);
Future<Boolean> result2=ser.submit(t2);
Future<Boolean> result3=ser.submit(t3);
//获取结果
boolean rs1= result1.get();
boolean rs2= result2.get();
boolean rs3= result3.get();
//关闭服务
ser.shutdownNow();
System.out.println(rs1);
System.out.println(rs2);
System.out.println(rs3);
}
@Override
public Boolean call() throws Exception
{
WebDownLoader wdl =new WebDownLoader();
wdl.webdownload(url, name);
System.out.println("下载了名为"+name+"的图片");
return true;
}
}
优点:
可以定义返回值
可以抛出异常
ps:Callable就是一个产生线程池的接口
总结:
三种方法调用多线程,以实现Runnable接口的方式居多,也更实用,实现Calable接口的方式在现阶段了解即可