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

java生成线程的四种方式

2016-10-13 15:49 351 查看
1、继承Thread类+重写run()方法

启动:创建子类对象+对象.start()

缺点:Java只支持单继承,如果我们的类已经从一个类继承,则无法再继承Thread类。

/**
* 模拟龟兔赛跑
* 1、创建多线程(方式一):继承 Thread + 重写run方法(线程体)
* 2、使用线程:创建子类对象  + 对象.start()方法  线程启动
*/

public class Demo01 {

public static void main(String[] args) {
//创建子类对象
Rabbit rab = new Rabbit();
Tortoise tor = new Tortoise();
//调用start方法 ,启动线程。 内部由CPU管控
rab.start(); //不要调用run方法,由内部自己调用。
tor.start();
for(int i=0;i<30;i++)
{
System.out.println("main-->"+i);
}
}
}

class Rabbit extends Thread{
//线程体  一切从run开始
@Override
public void run() {
//线程体
for(int i=0;i<30;i++)
{
System.out.println("兔子跑了"+i+"步");
}
}

}

class Tortoise extends Thread
{
@Override
public void run() {
//线程体
for(int i=0;i<30;i++)
{
System.out.println("乌龟跑了"+i+"步");
}
}
}


2、实现Runnable接口+重写run方法

启动:使用静态代理

1)、创建真实角色

2)、创建代理角色

3)、调用start()方法 启动线程

优点:可以同时实现继承,Runnable接口方式更加通用一些。

1、避免单继承的局限性

2、便于共享资源

通过实现Runnable接口实现多线程。(用到了静态代理设计模式)

/**
* 推荐使用Runnable创建线程
* 1、避免单继承的局限性
* 2、便于共享资源
*/
public class Demo03 {
public static void main(String[] args) {
//1)、创建真实角色
Programmer pro = new Programmer();
//2)、创建代理角色+真实角色引用
Thread proxy = new Thread(pro);
//3)、调用start()方法 启动线程
proxy.start();

for(int i=0;i<100;i++){
System.out.println("一边聊QQ");
}
}
}

/**
* 使用Runnable 创建进程
* 1、类实现Runable接口+重写run()方法
* 2、启动多线程 使用静态代理
*      1)、创建真实角色
*      2)、创建代理角色
*      3)、调用start()方法 启动线程
*/
class Programmer implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("一边敲代码");
}
}
}
/**
* 抢票系统
* 方便共享资源
*/
public class Demo04 implements Runnable{
private int num = 50;
@Override
public void run() {
while(true){
if(num<=0)
{
break;//跳出循环
}
System.out.println(Thread.currentThread().getName()+"抢到了倒数第"+num--+"张。");
}
}

public static void main(String[] args) {
//真实角色
Demo04 web = new Demo04();
//代理
Thread t1 = new Thread(web,"德玛西亚");
Thread t2 = new Thread(web,"卡特琳娜");
Thread t3 = new Thread(web,"德邦总管");

//启动线程
t1.start();
t2.start();
t3.start();
}
}


3、使用Callable接口创建多线程

Callable 和 Future接口

Callable是类似于Runnable的接口,实现*Callable接口的类和实现Runnable的类都是可被其它线程执行的任务*。

优点:可以返回值,可以抛异常。

缺点:实现繁琐。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
* 使用Callable接口方式创建多线程
*/
public class Demo05 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//1、创建线程
ExecutorService ser = Executors.newFixedThreadPool(2);//开两个线程

Race tortoise = new Race("老乌龟",1000);
Race rabbit = new Race("小兔子",500);

//2、获取Future对象
Future<integer> result1 = ser.submit(tortoise);
Future<integer> result2 = ser.submit(rabbit);

Thread.sleep(2000);//2秒
tortoise.setFlag(false);//停止线程体循环 设置flag = false;
rabbit.setFlag(false);
//3、获取值
int num1 = result1.get();
int num2 = result2.get();

System.out.println("乌龟跑了-->"+num1+"步");
System.out.println("兔子跑了-->"+num2+"步");
//4、停止服务
ser.shutdownNow();
}
}

class Race implements Callable<integer>
{
private String name;//名称
private long time;//延时时间
private boolean flag = true;
private int step = 0;//步

public Race() {
}
public Race(String name) {
super();
this.name = name;
}
public Race(String name, int time) {
super();
this.name = name;
this.time = time;
}

//有返回值了
@Override
public Integer call() throws Exception {
while(flag){
Thread.sleep(time);//延时
step++;
}
return step;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getTime() {
return time;
}
public void setTime(long  time) {
this.time = time;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public int getStep() {
return step;
}
public void setStep(int step) {
this.step = step;
}
}


4、应用程序可以使用Executor框架来创建线程池

import Java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPool {
private  static int POOL_NUM = 10;
public static void main(String[] agrs){
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < POOL_NUM; i++) {
RunnableThread thread = new RunnableThread();
executorService.execute(thread);
}
}
}
class RunnableThread implements  Runnable{
private   int THREAD_NUM = 10;
public void run() {
for (int i = 0; i <THREAD_NUM; i++) {
System.out.println("线程"+Thread.currentThread()+i);
}

}
}
几种方式的比较:

Callable和Runnable有几点不同:

(1)Callable规定的方法是call(),而Runnable规定的方法是run().

(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。

(3)call()方法可抛出异常,而run()方法是不能抛出异常的。

(4)运行Callable任务可拿到一个Future对象,Future表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。

实现Runnable接口相对于扩展Thread类来说,具有无可比拟的优势。这种方式不仅有利于程序的健壮性,使代码能够被多个线程共享,而且代码和数据资源相对独立,从而特别适合多个具有相同代码的线程去处理同一资源的情况。这样一来,线程、代码和数据资源三者有效分离,很好地体现了面向对象程序设计的思想。因此,几乎所有的多线程程序都是通过实现Runnable接口的方式来完成的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: