创建线程目的:
就是为了开辟一条路径,去运行指定的代码,指定的代码可以和其他代码同时运行。
运行的指定代码,封装在了run()方法中,这个指定代码就是线程任务
先看一个正常的程序
public class JVM {
public static void main(String[] args)
{
Person s1=new Person("张三");
Person s2=new Person("李四");
s1.run();
s2.run();
for(int i=1;i<=10;i++)
{
System.out.println("王五跑了第"+i+"圈");
}
}
}
class Person
{
private String name;
public Person(String name)
{
super();
this.name=name;
}
public void run()
{
for(int i=1;i<=10;i++)
{
System.out.println(name+"跑了第"+i+"圈");
}
}
}
执行结果是他们三个依次执行跑圈
这没有用到多线程,因为这是顺序执行
下面来创建多线程
比照着jdk API说明书,来实现一下
/*创建线程方式一:
步骤:
1.定义一个类继承Thread类
2.覆盖Thread类中的run()方法
3.直接创建Thread类实例对象
4.调用start()方法开启线程,并且调用run()方法
*/
package com.kuku;
class Person extends Thread{ //第一步定义一个类继承Thread
private String name;
public Person(String name)
{
super();
this.name=name;
}
@Override
public void run() { //重写Thread中的run方法
for(int i=1;i<=10;i++)
{
System.out.println(name+"跑了第"+i+"圈");
}
}
}
//然后在同一个包中创建另一个Java程序
package com.kuku;
public class TreadDemo2 {
public static void main(String[] args)
{
Person d1=new Person("小黄"); //开辟了一条线程
Person d2=new Person("小黑"); //开辟了一条线程
d1.start();
//不用d1.run();如果直接调用就是方法重写,则是顺序执行
d2.start();
}
}
多次执行结果为对比
/*第二种方式
步骤:
1.定义一个类实现Runnable接口
2.覆盖接口中的run方法
3.通过Thread类创建线程对象,并将Runnable接口的子类对象
作为Thread类的构造函数的参数传递过来
4.调用线程对象的start方法,开启线程
好处:
1.将线程的任务(例如run方法)从线程子类中分离出来,进行单独的分装
2.避免了Java单继承的局限性
*/
package com.kuku;
class Cat implements Runnable{
private String name;
public Cat(String name)
{
super();
this.name=name;
}
@Override
public void run() {
for(int i=1;i<=10;i++)
{
System.out.println(name+"跑了第"+i+"圈");
}
}
}
package com.kuku;
public class TreadDemo2 {
public static void main(String[] args)
{
Cat c1=new Cat("小橘橘");
Cat c2=new Cat("小虎斑");
new Thread(c1).start();
new Thread(c2).start();
}
}
多次测试结果
start()方法详解
特别注意:start只能同时调用一次,多次调用会抛出异常
//Thread运行原理(伪代码)
class Thraed{
private Runnable r;
Thread(){
}
Thread(Runnable r)
{
this.r=r;
}
void run()
{
if(r!==run)
{
r.run();
}
}
void start(){
run();
}
}
/*第一种方法(运用继承关系)
class Person 继承 Thread类{
//重写run方法
run(){
循环跑圈
}
}
main(){
实例化一个属于Thread类的对象时
调用start方法,而Thread里的run已经被重写,
所以start里的run()调用的是子类里的run方法
}
*/
/*第二种方法(接口)
class Person 实现 Runnable接口{
//此时不存在方法重写
run(){
循环跑圈
}
}
main(){
实例化一个Person类对象
调用Thread构造函数并传入Person类对象,
此时定义的Runnable类的r等于Person类对象
调用start方法,因为不存在方法的重写,所以start里的run是Thread里的run
而run方法里判断r!=成立,然后调用Person类里的run
}
*/