多线程
2 线程创建
2.2 实现Runnable接口
【学习提示】查看JDK帮助文档
- 定义MyRunnable类实现Runnable接口
- 实现run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
package com.duo.demo01;
//创建线程方式二:实现Runnable接口,重写run方法,执行线程需传入runnable接口实现类再调用start方法
public class ThreadTest3 implements Runnable {
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 5; i++) {
System.out.println("在写代码" + i);
}
}
public static void main(String[] args) {
//创建Runnable接口的实现类对象
ThreadTest3 threadTest3 = new ThreadTest3();
//创建线程对象,通过线程对象以启动线程
Thread thread = new Thread(threadTest3);
thread.start();
//上两行代码可简写为:new Thread(threadTest3).start();
for (int i = 0; i < 5; i++) {
System.out.println("在看视频" + i);
}
}
}
运行结果:
可以发现,主线程与所建线程同时执行,同样可以得出,线程开启后不一定立即执行,而由CPU调度执行。
在此基础上,在上节最后的练习”实现多线程同步下载图片“中,可将主线程函数中启动线程的代码体更换为:
public class ThreadTest2 implements Runnable {
public static void main(String[] args) {
ThreadTest2 t1 = new ThreadTest2("https://img-blog.csdnimg.cn/a4bbb67340ce46a293b725868b3997b4.jpeg", "星空.jpg");
ThreadTest2 t2 = new ThreadTest2("https://img-blog.csdnimg.cn/8dc90f70dca8437d868c655bcd0db7fc.jpeg", "黄昏.jpg");
ThreadTest2 t3 = new ThreadTest2("https://img-blog.csdnimg.cn/cc83486a8a7b46a193dac95decc4ad31.jpeg", "旷野.jpg");
new Thread(t1).start(); //更换后的启动线程代码
new Thread(t2).start();
new Thread(t3).start();
}
}
注意到在第一行代码中,已将原本的继承Thread类代码public class ThreadTest extends Thread {}
更新为实现Runnable接口的代码public class ThreadTest2 implements Runnable {}
,如此一来,原本直接调用线程对象threadTest的start()方法即threadTest.start()
可简化为如上的代码体new Thread(t1).start()
。
实际上,这种方法来创建一个线程是通过声明实现类Runnable
接口,在这个类中实现了run
方法。 然后可以分配类的实例,在创建Thread
时作为参数传递,并启动。
【小结】
-
继承Thread类方法
- 子类继承Thread类具备多线程能力
- 启动线程:子类对象.start()
- 不建议使用,OOP单继承局限性
-
实现Runnable接口
- 实现接口Runnable具有多线程能力
- 启动线程:传入目标对象 + Thread对象.start()
- 推荐使用,避免了单继承局限性,灵活方便,方便同一个对象被多个线程使用
-
初识并发问题
package com.duo.demo01;
import static java.lang.Thread.sleep;
//多个线程同时操作同一个对象
//买火车票的例子
public class ThreadTest4 implements Runnable {
private int ticketNum = 10;
@Override
public void run() {
while (ticketNum > 0) {
//模拟延时
try {
sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "->抢到了第" + ticketNum-- + "票");
}
}
public static void main(String[] args) {
ThreadTest4 ticket = new ThreadTest4();
new Thread(ticket, "ming").start();
new Thread(ticket, "hua").start();
new Thread(ticket, "hong").start();
}
}
运行结果:
可以发现,存在一个问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱 – 线程的并发问题