线程
线程是CPU调度和执行的单位。
(Main函数是主线程。)
线程的创建
继承Thread类的创建方式
- 自定义线程类继承Thead类
- 重写run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
//创建线程方式一:继承Thread类,重写run()方法,调用start()开启线程
public class Test01 extends Thread {
@Override
public void run() {
//run()方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在写代码----"+i);
}
}
public static void main(String[] args) {
//创建一个线程对象
Test01 test01 = new Test01();
test01.start();
//main线程,主线程
for (int i = 0; i < 200; i++) {
System.out.println("我在学习多线程-----"+i);
}
}
}
总结:线程开启不一定立即执行,由CPU调度执行
通过多线程同步下载网图(导入commons-io.jar)
//练习Thread,实现多线程同步下载图片
public class Test02 extends Thread {
private String name;
private String url;
public Test02(String url, String name){
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, name);
System.out.println("下载了文件名为:"+name);
//下载了文件名为:1.jpg
//下载了文件名为:3.jpg
//下载了文件名为:2.jpg
}
public static void main(String[] args) {
Test02 t1 = new Test02("https://img-blog.csdnimg.cn/20200802130504287.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hxMTgzMTg4NTk1NDE=,size_16,color_FFFFFF,t_70", "1.jpg");
Test02 t2 = new Test02("https://img-blog.csdnimg.cn/20200804015927727.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hxMTgzMTg4NTk1NDE=,size_16,color_FFFFFF,t_70", "2.jpg");
Test02 t3 = new Test02("https://img-blog.csdnimg.cn/20200803000039156.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hxMTgzMTg4NTk1NDE=,size_16,color_FFFFFF,t_70", "3.jpg");
t1.start();
t2.start();
t3.start();
}
}
//下载器
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方法出现问题");
}
}
}
实现Runnable接口
两者差别
火车票例子
//多个线程操作同一个对象例子:火车票
//发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱(初识并发问题)
public class Test04 implements Runnable {
//票数
private int ticketNum = 10;
@Override
public void run() {
while (true){
if (ticketNum<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"--拿到了第--"+ticketNum--+"--票");
}
}
public static void main(String[] args) {
Test04 ticket = new Test04();
new Thread(ticket,"小明").start();//Thread(对象,线程名)
new Thread(ticket,"小李子").start();
new Thread(ticket,"黄牛党").start();
}
}
/* 控制台输出:
小明--拿到了第--10--票
小明--拿到了第--8--票
小李子--拿到了第--9--票
小明--拿到了第--7--票
小明--拿到了第--5--票
小明--拿到了第--4--票
小明--拿到了第--3--票
小明--拿到了第--2--票
小明--拿到了第--1--票
小李子--拿到了第--6--票
*/
模拟龟兔赛跑例子
//模拟龟兔赛跑
public class Race implements Runnable {
//胜利者
private static String winner;
@Override
public void run() {
for (int i = 1; i < 1001; i++) {
boolean flag = gameOver(i);
if (flag){
break;
}
if (Thread.currentThread().getName().equals("兔子") && i == 600){
try {
System.out.println("兔子开始睡觉!");
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"--->跑了"+i+"米");
}
}
public boolean gameOver(int distance){
if (winner != null){
return true;
}else{
if (distance>=1000){
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接口
//线程创建方式三:实现callable接口
/*
callable的好处
1.可以定义返回值
2.可以抛出异常
*/
public class Test06 implements Callable<Boolean> {
private String name;
private String url;
public Test06(String url, String name){
this.url = url;
this.name = name;
}
@Override
public Boolean call() throws Exception {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, name);
System.out.println("下载了文件名为:"+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Test06 t1 = new Test06("https://img-blog.csdnimg.cn/20200802130504287.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hxMTgzMTg4NTk1NDE=,size_16,color_FFFFFF,t_70", "1.jpg");
Test06 t2 = new Test06("https://img-blog.csdnimg.cn/20200804015927727.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hxMTgzMTg4NTk1NDE=,size_16,color_FFFFFF,t_70", "2.jpg");
Test06 t3 = new Test06("https://img-blog.csdnimg.cn/20200803000039156.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hxMTgzMTg4NTk1NDE=,size_16,color_FFFFFF,t_70", "3.jpg");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> f1 = ser.submit(t1);
Future<Boolean> f2 = ser.submit(t2);
Future<Boolean> f3 = ser.submit(t3);
//获取结果
Boolean r1 = f1.get();
Boolean r2 = f2.get();
Boolean r3 = f3.get();
//关闭服务
ser.shutdown();
}
}
(文章通过狂神说视频内容进行总结。)