目录
Thread class ------ 继承Thread类(重点)
Runnable接口 ------ 实现Runnable接口(重点)
Callable接口 ------ 实现Callable接口(了解)
Thread class ------ 继承Thread类(重点)
创建流程:
1,自定义一个线程类继承Thread类
2,重写run()方法,编写线程执行体
3,创建线程对象,调用start()方法启动线程
普通方法调用和多线程解析:
1),调用run()方法就按调用执行,先run再执行下面的
public class TeatThread1 extends Thread {
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 200; i++) {
System.out.println("run---"+i);
}
}
public static void main(String[] args) {
//main线程,主线程
TeatThread1 teatThread1=new TeatThread1();
teatThread1.run();
for (int i = 0; i < 200; i++) {
System.out.println("main---"+i);
}
}
}
运行结果如下
2),调用start就是同时执行(切换速度很快)
public class TeatThread1 extends Thread {
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 2000; i++) {
System.out.println("run---"+i);
}
}
public static void main(String[] args) {
//main线程,主线程
//创建一个线程对象
TeatThread1 teatThread1=new TeatThread1();
//调用start方法开启线程
teatThread1.start();
for (int i = 0; i < 2000; i++) {
System.out.println("main---"+i);
}
}
}
执行结果如下:
注意:线程开启,不一定立即执行,由CPU调度执行
下载图片案例:
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TeatThread1 extends Thread {
private String url;
private String name;
public TeatThread1(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDounload webDounload=new WebDounload();
webDounload.douwload(url,name);
System.out.println("下载图片名=="+name);
}
public static void main(String[] args) {
TeatThread1 teatThread1=new TeatThread1("https://i-blog.csdnimg.cn/direct/abb2a9c994234586a2f732d60df0c497.png","1.jpg");
TeatThread1 teatThread2=new TeatThread1("https://i-blog.csdnimg.cn/direct/a5826a10c1d7454b99dcf23765942814.png","2.jpg");
TeatThread1 teatThread3=new TeatThread1("https://i-blog.csdnimg.cn/direct/c69117f268b443cab7990f09af65f6c1.png","3.jpg");
teatThread1.start();
teatThread2.start();
teatThread3.start();
}
}
//下载器
class WebDounload{
//下载方法
public void douwload(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("下载异常");
}
}
}
Runnable接口 ------ 实现Runnable接口(重点)
创建流程
1,实现Runnable接口
2,重写run方法
3,执行线程需要丢入runnable接口实现类
4,调用start方法
public class TestThread2 implements Runnable{
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 2000; i++) {
System.out.println("run=="+i);
}
}
public static void main(String[] args) {
//创建runnable接口实现类对象
TestThread2 testThread2=new TestThread2();
//创建线程对象,通过线程对象来开启线程,代理
// Thread thread=new Thread(testThread2);
// thread.start();
//以上两行代码简化为一行
new Thread(testThread2).start();
for (int i = 0; i < 2000; i++) {
System.out.println("main=="+i);
}
}
}
下载图片案例
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TeatThread1 implements Runnable {
private String url;
private String name;
public TeatThread1(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDounload webDounload=new WebDounload();
webDounload.douwload(url,name);
System.out.println("下载图片名=="+name);
}
public static void main(String[] args) {
TeatThread1 teatThread1=new TeatThread1("https://i-blog.csdnimg.cn/direct/abb2a9c994234586a2f732d60df0c497.png","1.jpg");
TeatThread1 teatThread2=new TeatThread1("https://i-blog.csdnimg.cn/direct/a5826a10c1d7454b99dcf23765942814.png","2.jpg");
TeatThread1 teatThread3=new TeatThread1("https://i-blog.csdnimg.cn/direct/c69117f268b443cab7990f09af65f6c1.png","3.jpg");
//相对继承Thread,修改行
new Thread(teatThread1).start();
new Thread(teatThread2).start();
new Thread(teatThread3).start();
}
}
//下载器
class WebDounload{
//下载方法
public void douwload(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("下载异常");
}
}
}
Thread和Runnable小结:
1,继承Thread类
1.1:子类继承Thread类具有多线程能力
1.2:启动线程:子列对象.start()
1.3:不建议使用,避免OOP单继承局限性
2,实现Runnable接口
2.1:实现Runnable接口具有多线程能力
2.2:启动线程:传入母变对象+Thread对象.start()
2.3:推荐使用:避免单继承局限性,灵活方便,方便同一个线程被多个线程使用
同一个线程被多线程使用的案例:买火车票
public class TestThread3 implements Runnable{
private int ticketNum=10;//定义票数
@Override
public void run() {
while (true){
//如果票没了,就停止
if(ticketNum<=0){
break;
}
//模拟一个延时,否则太快,看不出来同步执行
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获取当前线程名字Thread.currentThread().getName()
System.out.println(Thread.currentThread().getName()+"买到了第"+ticketNum--+"张票");
}
}
public static void main(String[] args) {
TestThread3 testThread3=new TestThread3();
//多个线程使用一个,第二个参数,可以给线程命名
new Thread(testThread3,"张三").start();
new Thread(testThread3,"李四").start();
new Thread(testThread3,"王麻子").start();
}
}
执行结果:可见就有人拿到重复的票,这就存在线程安全问题(多个线程操作同一个资源的情况下,线程不安全,数据紊乱)
此问题解决见后续笔记(CSDN)
Callable接口 ------ 实现Callable接口(了解)
创建流程
1,实现Callable接口,需要返回值类型
2,重写call方法,需要抛出异常
3,创建目标对象
4,创建执行服务:ExecutorService ser=Executors.newFixedThreadPool(1);
5,提交执行:Future<Boolean> result1-ser.submit(1);
6,获取结果:boolean r1=result1.get();
7,关闭服务:ser.shutDownNow();
下载图片案例
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
/**
* 1,实现Callable接口,需要返回值类型
* 2,重写call方法,需要抛出异常
* 3,创建目标对象
* 4,创建执行服务:ExecutorService ser=Executors.newFixedThreadPool(1);
* 5,提交执行:Future<Boolean> result1-ser.submit(1);
* 6,获取结果:boolean r1=result1.get();
* 7,关闭服务:ser.shutDownNow();
*/
public class TestThread5 implements Callable<Boolean> {
private String url;
private String name;
public TestThread5(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public Boolean call() {
WebDounload02 webDounload=new WebDounload02();
webDounload.douwload(url,name);
System.out.println("下载图片名=="+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestThread5 teatThread1=new TestThread5("https://i-blog.csdnimg.cn/direct/abb2a9c994234586a2f732d60df0c497.png","1.jpg");
TestThread5 teatThread2=new TestThread5("https://i-blog.csdnimg.cn/direct/a5826a10c1d7454b99dcf23765942814.png","2.jpg");
TestThread5 teatThread3=new TestThread5("https://i-blog.csdnimg.cn/direct/c69117f268b443cab7990f09af65f6c1.png","3.jpg");
//修改行
//创建一个线程池,放3个线程
ExecutorService ser= Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> submit1 = ser.submit(teatThread1);
Future<Boolean> submit2 = ser.submit(teatThread2);
Future<Boolean> submit3 = ser.submit(teatThread3);
//获取结果
boolean result1=submit1.get();
boolean result2=submit2.get();
boolean result3=submit3.get();
//关闭服务
ser.shutdownNow();
}
}
//下载器
class WebDounload02{
//下载方法
public void douwload(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("下载异常");
}
}
}
callable总结:可以定义返回值,可以抛出异常
原学习视频: