01.线程的简介
任务,线程,进程,多线程。
进程是程序的一次执行过程,他是一个动态概念。是系统分配资源的单位
通常一个进程中可以包含多个线程,当然一个线程中至少有一个进程
进程就好比你打开你的的微信,听歌,聊天,刷视频就都是一个线程,线程是cpu调度和执行的单位
02.线程的创建
第一种:继承Thread
//实现多线程:方式一:继承Thread,重写run()方法,调用start启动线程
//注意:线程开启不一定立即执行,由cpu的调度执行
public class TestThread extends Thread{
@Override
public void run() {
//run()方法
for (int i = 0; i < 100; i++) {
System.out.println("run方法"+i);
}
}
public static void main(String[] args) {
//创建线程调用run()方法
// new TestThread().run();//先执行run()方法
new TestThread().start();//运行看到 两个线程同步,交替执行
for (int i = 0; i < 100; i++) {
System.out.println("main方法"+i);
}
}
}
小案例:网图下载
第一步:需要导入common-iojar包
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//练习:网图下载
public class TestThread01 extends Thread {
private String url; //网图路径
private String name;//下载文件名
public TestThread01(String url,String name){
this.url = url;
this.name = name;
}
@Override
public void run() {
//调用下载器方法
DownLoader loader = new DownLoader();
loader.downLoader(url,name);
System.out.println("下载的文件名"+name);
}
public static void main(String[] args) {
TestThread01 t1 = new TestThread01("https://www.vfx123.com/wp-content/uploads/2020/08/b4e1301ff83eb95.jpg","1.jpg");
TestThread01 t2 = new TestThread01("https://uploadfile.huiyi8.com/2016/0418/20160418025010724.jpg","2.jpg");
TestThread01 t3 = new TestThread01("https://dfzximg01.dftoutiao.com/minimodify/20220713/731x431_62ce3f94a0dc4.png","3.png");
t1.start();
t2.start();
t3.start();
}
}
//下载器
class DownLoader{
//下载方法
public void downLoader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("downLoader方法出错");
}
}
}
第二种:实现Runnable接口
//实现多线程:方式二:实现Runnable接口,重写run()方法,调用start启动线程
public class TestThread02 implements Runnable{
@Override
public void run() {
//run()方法
for (int i = 0; i < 100; i++) {
System.out.println("run方法"+i);
}
}
public static void main(String[] args) {
//创建Runnable接口实现类 把他传进Thread构造器中 启动start
new Thread(new TestThread02()).start();
for (int i = 0; i < 100; i++) {
System.out.println("main方法"+i);
}
}
}
小结:
继承Thread类
子类继承Thread类具有多线程能力
启动线程:子类对象.start()
不建议使用:避免oop单继承局限性
实现Runnable接口
实现接口Runnable具有多线程能力
启动线程:传入目标对象+Thread对象.strat()
推荐使用:避免单继承局限性,灵活方便,方便对同一个对象被多个线程使用
初时并发问题
模拟购票
//多个线程操作同一个资源
//模拟购票
//发现问题 多个线程操作同一个资源 线程不安全,数据紊乱
public class TestThread03 implements Runnable{
private int tricks=10;
@Override
public void run() {
while (true){
if (tricks<=0){
break;
}
try {
//线程延迟
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Thread.currentThread().getName()获取当前线程的名字
System.out.println(Thread.currentThread().getName()+"拿到了第"+tricks--+"票");
}
}
public static void main(String[] args) {
TestThread03 testThread03 = new TestThread03();
new Thread(testThread03,"小明").start();
new Thread(testThread03,"小花").start();
new Thread(testThread03,"黄牛党").start();
}
}
小案例:龟兔赛跑
1.首先来个赛道距离,然后离终点越来越近
2.判断比赛是否结束
3.打印胜利者
4.龟兔赛跑开始
5.故事时乌龟赢了,兔子需要睡觉,所以模拟兔子睡觉
6.乌龟赢得比赛
package Demo01;
public class Race implements Runnable{
private static String winner;//胜利者
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
//模拟兔子睡觉
if (Thread.currentThread().getName().equals("兔子")&&i%10==0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
boolean flag = gameOver(i);
//比赛结束
if (flag){
break;
}
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
}
}
public boolean gameOver(int steps){
if (winner!=null){//已存在胜利者
return true;
}else if (steps>=100){//步数》=100比赛结束
winner = Thread.currentThread().getName();
System.out.println("winner is "+winner);
return true;
}
//比赛未结束
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
}
}
第三种:实现callable接口(了解)
1.实现callable接口,需要返回类型
2.重写call方法,需要抛出异常
3.创建目标对象
4.创建执行服务:ExecutorService service = Executors.newFixedThreadPool(3);
5.提交执行:Future<Boolean> r1 = service.submit(t1);
6.获取结果:Boolean rr1 = r1.get();
7.关闭服务:service.shutdownNow();
演示:利用callable改造下载图片案例
package Demo02;
import Demo01.TestThread01;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
public class TestCallable implements Callable<Boolean> {
private String url; //网图路径
private String name;//下载文件名
public TestCallable(String url,String name){
this.url = url;
this.name = name;
}
@Override
public Boolean call() {
//调用下载器方法
DownLoader loader = new DownLoader();
loader.downLoader(url,name);
System.out.println("下载的文件名"+name);