黑马程序员----多线程1(继承Thread类、实现Runnable接口)

来源:互联网 发布:淘宝网客户关系管理 编辑:程序博客网 时间:2024/06/04 19:27

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

多线程概述
进程:是一个正在执行中的程序。
每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。

线程:就是进程中的一个独立的控制单元。
线程在控制着进程的执行。

一个进程中至少有一个线程。

P.S.
1、一个进程中可以有多个执行路径,称之为多线程。
2、一个进程中至少要有一个线程。
3、开启多个线程是为了同时运行多部分代码,每一个线程都有自己运行的内容,这个内容可以称为线程要执行的任务。

多线程的好处:解决了多部分代码同时运行的问题。
多线程的弊端:线程太多,会导致效率的降低。
其实,多个应用程序同时执行都是CPU在做着快速的切换完成的。这个切换是随机的。CPU的切换是需要花费时间的,从而导致了效率的降低。

Java VM 启动的时候会有一个进程java.exe.
该进程中至少一个线程负责java程序的执行。
而且这个线程运行的代码存在于main方法中。
该线程称之为主线程。

扩展:其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回收机制的线程。

示例:

class Demo extends Object{       public void finalize(){            System.out.println("demo ok");       }}class ThreadDemo{       public static void main(String[] args){             new Demo();             new Demo();             System. gc();             new Demo();             System.out.println("Hello World!");      }}

运行结果
这里写图片描述
像这种情况,之所以先打印Hello World!再打印demo ok,是因为两条线程是分别执行的。

这里写图片描述
像这种情况,只打印一个demo ok,是因为在垃圾回收器还没回收第二个Demo对象的时候,JVM就已经结束了。

创建线程方式一—–继承Thread类

步骤:
1,定义类继承Thread。
2,复写Thread类中的run方法。
目的:将自定义代码存储在run方法。让线程运行。
3,调用线程的start方法,
该方法两个作用:启动线程,调用run方法。

多线程程序示例1:

class Demo extends Thread{    public void run()    {        for(int x=0; x<60; x++)            System.out.println("demo run----"+x);    }}class ThreadDemo {    public static void main(String[] args)     {        //for(int x=0; x<4000; x++)        //System.out.println("Hello World!");        Demo d = new Demo();//创建好一个线程。        //d.start();//开启线程并执行该线程的run方法。        d.run();//仅仅是对象调用方法。而线程创建了,并没有运行。        for(int x=0; x<60; x++)            System.out.println("Hello World!--"+x);    }}

运行结果先执行完”demo run—-“,再执行”Hello World!–”。

多线程程序示例2:

class Demo extends Thread{       private String name ;       Demo(String name){              this.name = name;       }        public void run(){              for(int x = 0; x < 10; x++){                   System.out.println(name + "...x=" + x + "...ThreadName=" + Thread.currentThread ().getName());             }       } } class ThreadDemo{        public static void main(String[] args){             Demo d1 = new Demo("旺财");             Demo d2 = new Demo("xiaoqiang");             d1.start(); //开启线程,调用run方法。             d2.start();             for(int x = 0; x < 20; x++){                   System.out.println("x = " + x + "...over..." + Thread.currentThread().getName());             }       } }

运行结果:
这里写图片描述

发现运行结果每一次都不同。
因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。
明确一点,在某一个时刻,只能有一个程序在运行。(多核除外)
cpu在做着快速的切换,以达到看上去是同时运行的效果。
我们可以形象把多线程的运行形容在互相抢夺cpu的执行权。

这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长,cpu说的算。

PS:
原来线程都有自己默认的名称。
Thread-编号 该编号从0开始。

static Thread currentThread():获取当前线程对象。
getName(): 获取线程名称。

设置线程名称:setName或者构造函数。

为什么要覆盖run方法呢?
Thread类用于描述线程。
该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。
也就是说Thread类中的run方法,用于存储线程要运行的代码。

线程运行状态
这里写图片描述

创建线程方式二:实现Runnable接口
步骤:
1,定义类实现Runnable接口
2,覆盖Runnable接口中的run方法。
将线程要运行的代码存放在该run方法中。
3,通过Thread类建立线程对象。
4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
为什么要将Runnable接口的子类对象传递给Thread的构造函数。
因为,自定义的run方法所属的对象是Runnable接口的子类对象。
所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。
5,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。

实现Runnable接口的好处:
1. 将线程的任务从线程的子类中分离出来,进行了单独的封装,按照面向对象的思想将任务封装成对象。
2. 避免了Java单继承的局限性。所以,创建线程的第二种方式较为常用。

示例:

//准备扩展Demo类的功能,让其中的内容可以作为线程的任务执行。 //通过接口的形式完成。 class Demo implements Runnable{       public void run(){             show();       }       public void show(){              for(int x = 0; x < 20; x++){                   System.out.println(Thread.currentThread().getName() + "..." + x);              }       } } class ThreadDemo{        public static void main(String[] args){             Demo d = new Demo();             Thread t1 = new Thread(d);             Thread t2 = new Thread(d);             t1.start();             t2.start();        } }

运行结果:
这里写图片描述

这里写图片描述

实现方式和继承方式有什么区别呢?
两种方式区别:
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable,线程代码存在接口的子类的run方法。

0 0
原创粉丝点击