package com.childers.thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/*
* 多线程下载多个图片
* 1. 创建类继承Thread,并重写run方法;
* 2. 在Download类下创建downloadImg方法;
* 3. 使用commons-io中的FileUtils.copyUrlToFile(Url,File)方法,根据参数做对应的下载操作;
* 4. 在run方法中调用downloadImg();
* 5. 在main方法中,new出Test02,通过有参构造传入对应的参数(url,fileName);
* 6. 执行start()方法;
* */
public class Test02 extends Thread{
//定义私有变量及构造函数,方便main方法中传参
private String fileName;
private String url;
public Test02(String fileName,String url){
this.fileName = fileName;
this.url = url;
}
@Override
public void run() {
Download download = new Download();
download.downloadImg(fileName,url);
System.out.println("下载了文件名为"+fileName);
}
public static void main(String[] args) {
Test02 dl1 = new Test02("第一个.jpg", "https://pic.downk.cc/item/5fca0303394ac523782d2256.jpg");
Test02 dl2 = new Test02("第二个.jpg", "https://pic.downk.cc/item/5fca0303394ac523782d2259.jpg");
Test02 dl3 = new Test02("第三个.jpg", "https://pic.downk.cc/item/5fca0303394ac523782d225e.jpg");
dl1.start();
dl2.start();
dl3.start();
}
}
class Download{
public void downloadImg(String fileName,String url){
try {
//commons-io
FileUtils.copyURLToFile(new URL(url),new File(fileName));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,downloadImg方法有问题");
}
}
}
/*
* 多线程下载多个图片
* 1. 创建类实现Runnable接口,并重写run方法;
* 2. 在Download类下创建downloadImg方法;
* 3. 使用commons-io中的FileUtils.copyUrlToFile(Url,File)方法,根据参数做对应的下载操作;
* 4. 在run方法中调用downloadImg();
* 5. 在main方法中,new出Test02,通过有参构造传入对应的参数(url,fileName);
* 6. new出Thread,传入Runnable类型的参数(实现了Runnable接口的本测试类)
* 7. 调用Thread的start()方法
* */
public class Test03 implements Runnable{
private String url;
private String fileName;
public Test03(String url, String fileName) {
this.url = url;
this.fileName = fileName;
}
@Override
public void run() {
DownLoad downLoad = new DownLoad();
downLoad.downloadImg(url,fileName);
System.out.println("下载的是"+fileName);
}
public static void main(String[] args) {
Test03 t01 = new Test03("https://pic.downk.cc/item/5fca0303394ac523782d2256.jpg","第一个.jpg");
Test03 t02 = new Test03("https://pic.downk.cc/item/5fca0303394ac523782d2259.jpg","第二个.jpg");
Test03 t03 = new Test03("https://pic.downk.cc/item/5fca0303394ac523782d225e.jpg","第三个.jpg");
new Thread(t01).start();
new Thread(t02).start();
new Thread(t03).start();
}
}
/*
* 实现过程:
* 1. 实现Callable接口,需要泛型,泛型就是线程执行完后的返回值类型(call方法的返回值类型);
* 2. Executors.newFixedThreadPool(2)创建一个固定线程池,线程有两个;
* 3. Executors.newFixedThreadPool(2).submit(Callable)执行线程;
* 4. 通过上面的返回值.get()获取线程的返回值;
* 5. 关闭线程池:.shutdown()
* */
public class TestCallable implements Callable<Person> {
//是否存在Winner
private static boolean hasWinner;
@Override
public Person call() throws Exception {
//for循环给线程执行计数
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "跑了" + i + "步");
int race = race(i);
if (race == 1) {//返回值为1,当前线程赢了
//返回Person对象
return new Person(Thread.currentThread().getName(), true);
} else if (race == -1) {//返回值为-1,当前线程输了,返回对象
return new Person(Thread.currentThread().getName(), false);
}
}
return null;
}
public int race(int step) {
if (hasWinner) {
return -1;//已经存在winner,当前线程输了,返回-1
} else if (step >= 100) {
hasWinner = true;
return 1;//当前线程赢了,返回1
}
return 0;//没有人胜出,返回0
}
public static void main(String[] args) {
TestCallable testCallable = new TestCallable();
//创建固定的线程池,大小为2
ExecutorService executorService = Executors.newFixedThreadPool(2);
//执行线程
Future<Person> submit1 = executorService.submit(testCallable);
Future<Person> submit2 = executorService.submit(testCallable);
try {
//获取线程的返回值
Person person1 = submit1.get();
Person person2 = submit2.get();
//关闭线程池
executorService.shutdown();
//哪个Person对象赢了,就打印该对象赢了,另外一个输了
if (person1.getWin()) {
System.out.println(person1.getName() + "赢了!");
System.out.println(person2.getName() + "输了!");
} else {
System.out.println(person2.getName() + "赢了!");
System.out.println(person1.getName() + "输了!");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
推荐使用第二种(实现Runnable接口);
首先,第一种方式是继承,就受单继承规则的局限性;
那么第二种方式,不受单继承的局限,方便多线程对同一个对象的使用。
/*
* 龟兔赛跑情景模拟:
* 1. 创建线程
* 2. 在run()方法中定义了for循环,模拟参赛者的步数(线程执行的计数);
* 3. 默认两个线程都会各自执行100次;
* 4. 根据分析,只要有一个线程的执行次数达到了100次以上,就终止全部线程;
* 5. 在race()方法中,进行了对winner的判断;
* 6. 如果值为空,说明没有胜利者(没有线程执行够100次);则返回false,线程继续执行;
* 7. 如果值为空,且当前线程的执行次数到达了100次,则给winner赋值为当前线程的name,并返回true,终止本线程;
* 8. 当另一个线程执行过来后,发现值不为空,说明已经有别的线程访问够了100次,则返回true终止本线程;
* */
public class Race implements Runnable {
private static String winner;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "跑了" + i + "步");
boolean race = race(i);
if (race) {
break;
}
}
}
public boolean race(int step) {
if (winner != null) {
return true;
}else if (step >= 100) {
winner = Thread.currentThread().getName();
System.out.println(winner + "赢了!");
return true;
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race, "乌龟").start();
new Thread(race, "兔子").start();
}
}
原文:https://www.cnblogs.com/childers/p/14256792.html