多线程的实现方式有三:继承Thread、实现Runnable接口、实现Callable
1、继承Thread类
- 子类继承Thread类具备多线程 的能力
- 启动线程:子类对象名.start();
- 不建议使用:避免OOP单继承局限性
package Thread_demo1;
public class Demo1 extends Thread{
// 创建线程的方式一:继承Thread类,重写run()方法,调用start开启线程
// 总结:注意,线程开启不一定立即执行,由CPU调度
@Override
public void run(){
// run方法线程体
for (int i = 0;i < 10;i++){
System.out.println("我是run方法"+i);
}
}
public static void main(String[] args) {
// main线程,主线程
// 创建一个线程对象
Demo1 thread1 = new Demo1();
// 调用start()方法开启线程
thread1.start();
for (int i = 0;i < 200;i++){
System.out.println("我是main方法"+i);
}
}
}
2、实现Runnable接口
- 实现接口Runnable具有多线程能力
- 启动线程:传入目标对象+Thread对象.start();
- 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
- 一份资源,多个代理。
4
//多个线程同时操作同一个对象
//买火车票例子
//存在问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱
public class TestThread4 implements Runnable{
// 总票数
private int ticketNames = 20;
@Override
public void run() {
while (true){
if(ticketNames<=0){
break;
}
try{
Thread.sleep(300);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--->拿到了第"+ticketNames-- +"张票");
}
}
public static void main(String[] args) {
TestThread4 T = new TestThread4();
new Thread(T,"A").start();
new Thread(T,"B").start();
new Thread(T,"C").start();
new Thread(T,"D").start(); }}
public class TestThread2 implements Runnable {
public void run(){
// run方法线程体
for (int i = 0;i < 10;i++){
System.out.println("我是run方法"+i);
}
}
public static void main(String[] args) {
TestThread2 t1 = new TestThread2();
new Thread(t1).start();
}
}
3、实现Callable接口
- 实现Callable接口,需要返回值类型
- 重写call方法,需要抛出异常
- 创建目标对象
- 创建执行服务:ExecutorService ser = Executor.newFixedThreadPool(1);
- 提交执行:Future result = ser.submit(t1);
- 获取结果:Boolean r1 = result.get();
- 关闭服务:ser.shutdownNow();
package Thread_demo6;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
//练习Thread ,实现多线程同步下载图片
//public class TestThread2 extends Thread {
//练习实现Runnable ,实现多线程同步下载图片,启动方式:Thread(对象名).start();
public class TestThread6 implements Callable<Boolean> {
private String url;//网络图片的地址
private String name;//保存的文件名
public TestThread6(String url, String name) {
this.url = url;
this.name = name;
}
//下载图片的执行体
@Override
public Boolean call() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, name);
System.out.println("下载了文件名为:" + name);
return true;
}
public static void main(String[] args) throws ExecutionException,InterruptedException{
TestThread6 t1 = new TestThread6("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fup.enterdesk.com%2Fphoto%2F2010-6-26%2Fenterdesk.com-4B252A6CF906073A3BB9A31630A084EB.jpg&refer=http%3A%2F%2Fup.enterdesk.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1650286306&t=b9792498c6e05ce7b8478aed1a4f7763", "1.jpg");
TestThread6 t2 = new TestThread6("https://img1.baidu.com/it/u=2424432553,812276981&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500", "2.jpg");
TestThread6 t3 = new TestThread6("https://marketplace.canva.cn/D2h5Y/MAE2CkD2h5Y/1/tl/canva-%E6%98%A5%E5%AD%A3%E8%8A%82%E6%B0%94%E5%B0%8F%E5%9C%BA%E6%99%AF%E6%8F%92%E7%94%BB-%E6%B8%85%E6%98%8E-MAE2CkD2h5Y.png", "3.jpg");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
// 5. 提交执行:
Future<Boolean> result1 = ser.submit(t1);
Future<Boolean> result2 = ser.submit(t2);
Future<Boolean> result3 = ser.submit(t3);
// 6. 获取结果:
boolean rs1 = result1.get();
boolean rs2 = result1.get();
boolean rs3 = result1.get();
// 7. 关闭服务:
ser.shutdownNow();
}
}
//下载器
class WebDownloader{
// 下载方法
public void downloader(String url,String name){
try{
FileUtils.copyURLToFile(new URL(url),new File(name));
}catch (IOException e){
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题");
}
}
}