1、写在前面
在此记录,以备遗忘
2、核心要点
2.1、Thread和Runnable哪一个更好
2.2、Runable的优势-多线程内部数据共享
2.3、启动顺序和执行结果顺序
2.4、创建线程的疑惑:new Thread()和new Thread(Runnable接口实现类对象)的区别
3、具体操作
3.1、Thread和Runnable哪一个更好
3.1.1、源码分析
核心源码如下【进行过代码裁剪】:继承于Thread并实现它的run方法能创建一个线程,实际这个run方法就是Runnable所提供的代理对象所有的,因此我们可以得到Runnable的全部优点
public class Thread implements Runnable {
private Runnable target;
private native void start(){
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
}
3.1.2、Runable的优势总结
1.【多线程内部数据共享】适合多个相同程序代码的线程去处理同一个资源(多线程内的数据共享)
2.【继承】避免java特性中的单根继承限制
3.【解耦】增加程序健壮性,数据被共享时,仍然可以保持代码和数据的分离和独立
4.【设计】更能体现java面向对象的设计特点
3.2、Runable的优势-多线程内部数据共享
3.2.1、错误的线程并发案例【Thread实现】
每个线程拥有自己的变量,线程之间没有共享数据
public class Test03ThreadMain extends Thread {
private int count = 5;
@Override
public void run() {
for (int i = 0; i < 7; i++) {
if (count > 0) {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + "----currentIndex:" + (count--));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Test03ThreadMain h1 = new Test03ThreadMain();
Test03ThreadMain h2 = new Test03ThreadMain();
Test03ThreadMain h3 = new Test03ThreadMain();
h1.start();
h2.start();
h3.start();
}
}
3.2.2、正确的线程并发案例【Runable实现】
public class Test03ThreadRunable implements Runnable{
private int count = 5;
@Override
public void run() {
for (int i = 0; i < 7; i++) {
if (count > 0) {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + "----currentIndex:" + (count--));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 一个执行任务,让多个线程进行执行
public static void main(String[] args) {
Test03ThreadRunable runable = new Test03ThreadRunable();
new Thread(runable, "1号窗口").start();
new Thread(runable, "2号窗口").start();
new Thread(runable, "3号窗口").start();
}
}
3.3、启动顺序和执行结果顺序
尽管启动线程的顺序是有序的,但是执行的顺序并非是有序的。也就是说,1号线程并不一定是第一个将自己名字输出到控制台的线程。这是因为线程是并行执行而非顺序的。【Jvm和操作系统一起决定了线程的执行顺序,他和线程的启动顺序并非一定是一致的。】
3.4、创建线程的疑惑:new Thread()和new Thread(Runnable接口实现类对象)的区别
public class ThreadDemo2 {
public static void main(String[] args) {
// 创建Ruanbel对象【Thread也是Runable的实现】
myThread myThread=new myThread();
myThread.setName("B");
// 创建Thread进行执行
Thread thread=new Thread(myThread);
thread.setName("A");
thread.start();
}
}
class myThread extends Thread{
@Override
public void run() {
System.out.println("返回正在执行该代码的线程名称:"+Thread.currentThread().getName());
System.out.println("当前线程对象的名称:"+this.getName());
}
}
执行结果:
- 返回正在执行该代码的线程名称【Thread.currentThread().getName())】:A
- 当前线程对象的名称【this.getName()】:B
执行结果分析:
- 1)正常代码中都是使用Thread.currentThread().getName()),所以无论Runable执行的名称是什么,都不会影响我们对线程名称的打印
-2)查看源码:target指向的【传入Thread的Runable对象】,所有用this进行打印,返回的是Runbale的名称【Runable本身没有名称,但是实现类Thread有名称,所以如果Thread有名称,就直接被this.name打印出来】 - 3)Thread.currentThread()代指的逻辑就是new Thread(),所以打印A就很好理解了
4、课后习题
4.1、Thread和Runnable对比分析?从代码层面进行解析
参考本文的3.1章节
4.2、多线程内部数据共享,用代码进行实现
5、参考网址
- 【Thread和Runnable你该选哪个】:https://blog.csdn.net/phantomes/article/details/8848148
- 【new Thread()和new Thread(Runnable接口实现类对象)的区别】:https://blog.csdn.net/qq_39957294/article/details/88077112
网友评论