Thread class 继承Thread(重点)
创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。
继承类必须重写 run() 方法,该方法是新线程的入口点。
它也必须调用 start() 方法才能执行。
该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。
//创建线程方法一:继承Thread类,重写Run()方法,调用start()开启线程
public class TestThread01 extends Thread{
@Override
public void run() {
//run方法线程体
for (int i=0;i<200;i++){
System.out.println("线程" + i);
}
}
public static void main(String[] args) {
//main线程,主线程
//创建一个线程对象
TestThread01 testThread01 = new TestThread01();
//调用start()方法开启线程
testThread01.start();
for (int i=0;i<2000;i++){
System.out.println("线程ar" + i);
}
}
}
线程会穿插在主线程中出现
总结:线程开启不一定立即执行,由CPU调度执行
线程在主线程ar中穿插执行,且每次位置也可能不同,由CPU决定
多线程下载(IDM)
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TestThread02 extends Thread {
private String url;//网络图片地址
private String name;//保存的文件名
public TestThread02(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);
}
public static void main(String[] args) {
TestThread02 testThread02 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","2.png");
TestThread02 testThread03 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","3.png");
TestThread02 testThread04 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","4.png");
testThread02.start();
testThread03.start();
testThread04.start();
}
}
//下载器
class WebDownLoader{
//下载方法
public void downloader(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
System.out.println("io异常,downloader方法出现异常");
}
}
}
(同时执行,不一定按顺序,是根据下好的时间来排的)
Runnable接口 实现Runnable接口(重点)
//改的第一个
public class TestThread03 implements Runnable{
@Override
public void run() {
//run方法线程体
for (int i=0;i<200;i++){
System.out.println("线程" + i);
}
}
public static void main(String[] args) {
//创建一个Runnable接口的实现类对象
TestThread03 testThread03 = new TestThread03();
// //创建线程对象,通过线程对象打开线程,代理
// Thread thread = new Thread(testThread03);
// thread.start();
new Thread(testThread03).start();
for (int i=0;i<1000;i++){
System.out.println("线程ar" + i);
}
}
}
//改的第二个
public class TestThread02 implements Runnable {
private String url;//网络图片地址
private String name;//保存的文件名
public TestThread02(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);
}
public static void main(String[] args) {
TestThread02 testThread02 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","2.png");
TestThread02 testThread03 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","3.png");
TestThread02 testThread04 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","4.png");
new Thread(testThread02).start();
new Thread(testThread03).start();
new Thread(testThread04).start();
}
}
//下载器
class WebDownLoader{
//下载方法
public void downloader(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
System.out.println("io异常,downloader方法出现异常");
}
}
}
对比:继承Thread VS Runnable()
继承Thread类
- 子类继承Thread类具备多线程能力
- 启动线程:子类对象. start()
- 不建议使用:避免OOP单继承局限性
实现Runnable接口
- 实现接口Runnable具有多线程能力
- 启动线程:传入目标对象+Thread对象.start()
- 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
并发
//数据不安全,会出现紊乱,
public class TestThread04 implements Runnable {
//票数
private int ticksNums=10;
@Override
public void run() {
while (true){
if (ticksNums<=0){
break;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了" + ticksNums-- + "票");
}
}
public static void main(String[] args) {
TestThread04 ticket = new TestThread04();
new Thread(ticket,"ar").start();
new Thread(ticket,"kimi").start();
new Thread(ticket,"alice").start();
}
}
ar抢到了9票
kimi抢到了8票
alice抢到了10票
ar抢到了7票
alice抢到了6票
kimi抢到了7票
alice抢到了5票
kimi抢到了4票
ar抢到了3票
alice抢到了2票
ar抢到了2票
kimi抢到了2票
alice抢到了1票
ar抢到了-1票
kimi抢到了0票
龟兔赛跑
import java.lang.Thread;
import java.lang.Runnable;
class Rabbit implements Runnable{
private String name;
static int rabbit_walk=0; //兔子跑过的距离
public Rabbit(String name) {
this.name=name;
}
public String getName(){
return this.name;
}
public synchronized void run() {
System.out.println("兔子开始跑了...");
for(int i=0;i<=500;i+=5) {
System.out.println(this.getName()+"跑了"+i+"米");
if(i%20==0) {
try {
Thread.sleep(50);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
rabbit_walk+=5;
if(Tortoise.tortoise_walk==500)
break;
if(i==500) {
System.out.println(this.getName()+"跑完了全程");
System.out.println("胜利者是"+this.getName());
}
}
return;
}
}
class Tortoise implements Runnable{
private String name;
static int tortoise_walk=0; //乌龟跑过的距离
public Tortoise(String name) {
this.name=name;
}
public String getName() {
return this.name;
}
public synchronized void run() throws NullPointerException{
System.out.println("乌龟开始跑了...");
for(int i=0;i<=500;i++) {
System.out.println(this.getName()+"跑了"+i+"米");
if(i%500==0) {
try {
Thread.sleep(500);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
Tortoise.tortoise_walk+=1;
if(Rabbit.rabbit_walk==500)
break;
if(i==500) {
System.out.println(this.getName()+"跑完了全程");
System.out.println("胜利者是"+this.getName());
}
}
return;
}
}
class Runtest {
public static void main(String[] args) {
Thread t1 = new Thread(new Rabbit("兔子"));
Thread t2 = new Thread(new Tortoise("乌龟"));
t1.start();
t2.start();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SyFzxNT6-1639908403095)(C:\Users\17730\AppData\Roaming\Typora\typora-user-images\image-20211219175902111.png)]
Callable接口 实现Callable接口(了解)
当实现Callable接口之后,要重写接口中的call方法,call方法中的代码作为线程执行体,此时的call方法可以有返回值。
Callable接口是Java5中新增的接口,不是Runnable接口的子接口,所以Callable对象不能直接作为Thread对象的Target,于是Java5中提供了Future接口来代表Callable接口里call方法的返回值,并为Future接口提供了一个FutureTask实现类,它实现了Future接口和Runnable接口,可以作为Thread类的Target。所以在创建Callable
接口实现类之后,要用FutureTask来包装Callable对象(实现手动装箱)。然后用FutureTask对象作为Target。
Callable接口是Java5中新增的接口,不是Runnable接口的子接口,所以Callable对象不能直接作为Thread对象的Target,于是Java5中提供了Future接口来代表Callable接口里call方法的返回值,并为Future接口提供了一个FutureTask实现类,它实现了Future接口和Runnable接口,可以作为Thread类的Target。所以在创建Callable
接口实现类之后,要用FutureTask来包装Callable对象(实现手动装箱)。然后用FutureTask对象作为Target。