您的位置:首页 > 编程语言 > Java开发

Java多线程之创建任务和线程

2016-12-14 17:19 417 查看

Runnable创建线程

任务就是对象。为了创建任务,必须首先为任务定义一个类。任务类必须实现Runnable接口。Runnable接口非常简单,它只包含一个run方法。需要实现这个方法来告诉系统线程将如何运行。开发一个任务类的模板如图29-2a所示。

一旦定义了一个TaskClass,就可以用它的构造方法创建一个任务。例如,

TaskClass task = new TaskClass(...);


任务必须在线程中执行。Thread类包括创建线程的构造方法以及控制线程的很多有用的方法。使用下面的语句创建任务的线程:

Thread thread = new Thread(task);


然后调用start()方法告诉Java虚拟机该线程准备运行,如下所示:

thread.start();


Java虚拟机通过任务的run()方法执行任务。图29-2b概括了创建一个任务,一个线程以及开始线程的主要步骤。



下面例子给出一个程序,它创建三个任务以及运行这三个任务的线程:

第一个任务打印字母a100次

第二个任务打印字母b100次

第三个任务打印1~100的整数。

如果运行这个程序,则三个线程将共享CPU,并且在控制台上轮流打印字母和数字。

package chapter29;

public class TaskThreadDemo
{
public static void main(String[] args)
{
//Create tasks
Runnable printA = new PrintChar('a',100);
Runnable printB = new PrintChar('b',100);
Runnable print100 = new PrintNum(100);

//Create threads
Thread thread1 = new Thread(printA);
Thread thread2 = new Thread(printB);
Thread thread3 = new Thread(print100);

//Start threads
thread1.start();
thread2.start();
thread3.start();
}
}

//The task for printing a character a specified number of times
class PrintChar implements Runnable
{
private char charToPrint;//The character to print
private int times;//The number of times to repeat

/*
* Construct a task with specified character to print
* times to print the character
*/
public PrintChar(char c,int t)
{
charToPrint = c;
times = t;
}

/*
* Override the run() method to tell the system
* what task to perform
*/
public void run()
{
for(int i = 0; i < times; i++)
{
System.out.println(charToPrint);
}
}
}

//The task class for printing numbers from 1 to n for a given n
class PrintNum implements Runnable
{
private int lastNum;

/*Construct a task for printing 1,2,.....n*/
public PrintNum(int n)
{
lastNum = n;
}

/*Tell the thread how to run*/
public void run()
{
for(int i = 1; i <= lastNum; i++)
{
System.out.println(" " + i);
}
}
}


该程序创建了三个任务。为了同时运行它们,创建三个线程。调用start()方法启动一个线程,它会导致任务中的run()方法被执行。当run()方法执行完毕,线程就终止。

因为前两个任务printA和printB有类似的功能,所以它们可以定义在同一个任务类PrintChar中。PrintChar类实现Runnable,并且覆盖run()方法,使之具备打印字符动作。该类提供根据给定次数打印任意单个字符的框架。可运行对象printA和printB都是PrintChar类的实例。

PrintNum类实现Runnable,并且覆盖run()方法,使之具备打印数字的动作。该类提供对于任意整数n,打印从

1到n的整数的框架。可运行对象print100是PrintNum类的一个实例。

注意:如果看不到并发运行三个线程的效果,那么就要增加打印字符的个数。例如:

Runnable printA = new PrintChar('a',10000);


package heima;

/*
* 需求:简单的卖票程序
* 多个窗口同时买票
*
* 创建线程的第二种方式:实现Runnable接口
*
* 步骤:
* 1.定义类实现Runnable接口
* 2.覆盖Runnable接口中的run方法。
*   将线程要运行的代码存放在该run方法中。
* 3.通过Thread类建立线程对象。
* 4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
*   为什么要将Runnable接口的子类对象传递给Thread的构造函数。
*   因为:自定义的run方法所属的对象是Runnable接口的子类对象
*   所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。
* 5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
*
* 实现方式和继承方式有什么区别呢?
*
* 实现方式好处:避免了单继承的局限性。
* 在定义线程时,建议使用实现方式。
*
* 两种方式区别:
* 继承Thread:线程代码存放Thread子类run方法中
* 实现Runnable,线程代码存在接口的子类的run方法中。
*/
class Ticket implements Runnable
{
private int tick = 100;
public void run()
{
while(true)
{
if(tick > 0)
{
System.out.println(Thread.currentThread().getName() + "......sale : " + tick--);
}
}
}
}

public class TicketThread
{
public static void main(String[] args)
{
Ticket t = new Ticket();

Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
/*Ticket t1 = new Ticket();
Ticket t2 = new Ticket();
Ticket t3 = new Ticket();
Ticket t4 = new Ticket();

t1.start();
t2.start();
t3.start();
t4.start();*/
}
}


创建线程的另一种方法:Thread类

Thread类包含为任务而创建的线程的构造方法,以控制线程的方法。



步骤:
1.定义类继承Thread,
2.复写Thread类中的run方法,
目的:将自定义代码存储在run方法。让线程运行。
3.调用线程的start方法,
该方法两个作用:启动线程,调用run方法
发现运行结果每一次都不同,
因为多个线程都获取cpu的执行权,cpu执行到谁,谁就运行。明确一点,在某一时刻,只能有一个程序在运行,(多核除外)
cpu在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象把多线程的运行认为在互相抢夺cpu的执行权。

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

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

也就是说Thread类中的run方法,用于存储线程要运行的代码。

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)
{
Demo d = new Demo();//创建好一个线程。
d.start();//开启线程并执行该线程的run方法
//d.run();//仅仅是对象调用方法,而线程创建了,并没有运行。

for(int x = 0; x < 60; x++)
System.out.println("Hello World!--" + x);
}
}




/*
练习:
创建两个线程,和主线程交替运行。
*/
class Test extends Thread
{
private String name;
Test(String name)
{
this.name = name;
}
public void run()
{
for (int x = 0; x < 60; x++)
{
System.out.println(name + " run..." + x);
}
}
}

public class ThreadTest
{
public static void main(String[] args)
{
Test t1 = new Test("one");
Test t2 = new Test("two");
t1.start();
t2.start();
//t1.run();
//t2.run();

for(int x = 0; x < 60; x++)
{
System.out.println("main......" + x);
}
}
}


线程的运行状态



获取线程对象及名称

package heima;

/*
* 原来线程都有自己默认的名称
* Thread-编号 该编号从0开始。
*
* static Thread currentThread():获取当前线程对象。
* getName():获取线程名称
*
* 设置线程名称:setName或者构造函数。
*/
class Test extends Thread
{
private String name;
Test(String name)
{
this.name = name;
}
public void run()
{
for (int x = 0; x < 60; x++)
{
System.out.println((Thread.currentThread() == this) + "..." + this.getName() + " run..." + x);
}
}
}

public class ThreadTest
{
public static void main(String[] args)
{
Test t1 = new Test("one");
Test t2 = new Test("two");
t1.start();
t2.start();
//t1.run();
//t2.run();

for(int x = 0; x < 60; x++)
{
System.out.println("main......" + x);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  多线程