线程创建的四种方式+具体案例

JDK5.0之前

1、继承于Thread类创建线程

1.1、继承Thread类创建线程案例

/**
 * 多线程创建方式一:继承于Thread类
 * 1、创建继承于Thread类的子类
 * 2、重写Thread类的run() ---->在此线程的操作在run()中
 * 3、创建Thread类的子类对象
 * 4、通过此对象调用start()
 * 例子遍历100以内的所有偶数
 */
class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <100 ; i++) {
            if(i%2 == 0){
                System.out.println(Thread.currentThread().getName()+"***"+i+"******MyThread.start*****");
            }
        }
    }
}
public class ThreadTest {
    public static void main(String[] args) {
        //创建Thread的子类对象
        MyThread t1 =  new MyThread();
        //通过此对象调用start():1、启动当前线程 2、调用当前线程的run()
        t1.start();
        //如下操作仍是在main线程中执行
        for (int i = 0; i <100 ; i++) {
            if(i%2 == 0){
                System.out.println(Thread.currentThread().getName()+i+"*********Main.start*******");
            }
        }
    }
}

1.2、线程的常用方法

1、start(): 启动当前线程 ;调用当前线程的run()

2、run(): 通常需要重写Thread类中的此方法,将创建的创建线程需要执行的操作在此方法中声明

3、currentThread()静态返回执行当前代码的线程,在Thread子类中就是this通常用于主线程和Runnable类实现

4、getName():获取当前线程的名字

5、setName():设置当前线程的名字

6、yield(): 静态,线程让步。

  • 暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程
  • 若队列中没有同优先级的线程,忽略此方法

7、join():当前某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到join()方法加入的join线程指向完为止

  • 低优先级的线程也可以获得执行

8、sleep():(指定时间:毫秒):

  • 令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排序
  • 抛出InterruptedException异常

9、stop(): 强制线程声明期结束,不推荐使用

10、isAlive(): 返回boolan,判断线程是否还活着

1.3、线程调度及优先级的概念

线程调度的策略:

  • 时间片:

image.png

  • 抢占式:高优先级的线程抢占CPU

java的调度方法:

  • 同优先级线程组成先进先出(先到先服务),使用时间片策略
  • 对高优先级,使用优先调度的抢占式策略

线程的优先级:

线程优先级等级:  MAX_PRORITY:10    MIN_PRORITY:1  MORE_PRORITY:1

涉及的方法: getPriority():返回线程的优先级           setPriority(int newPriority):改变线程的优先级

说明:

线程创建时继承父类线程的优先级

低优先级只是为获得调度的概率底,并非一定是在高优先级线程之后才被调用

2、实现Runnable接口创建线程

2.1、实现Runnable接口创建线程案例

//创建实现Runnable接口的类
class MThread implements Runnable {
    @Override
    //实现Runnable中的抽象方法:run()
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + "****" + i);
            }
        }
    }
}
public class ThreadRuaable {
    public static void main(String[] args) {
        //3、创建类的实例对象
        MThread mt =  new MThread();
        //4、将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
        Thread thread = new Thread(mt);
        //5、通过Thread类的对象调用start()
        thread.start();
        Thread thread2 = new Thread(mt);
        thread2.start();

    }
}

JDK5.0新增线程创建方式

1、新增方式一:实现Callable接口:

1.1、Callable比Runnable的功能更强大:

1、call()可以有返回值

2、call()可以抛出异常,被外面的操作捕获,获取异常信息

3、callable是支持泛型的

4、需要借助FutureTask类,比如获取返回值

1.2、Future接口

  • 可以对具体的Runnable、Callable任务的执行结果进行取消、查询是否完成,获取结果等
  • FutureTask是Future接口的唯一的实现类
  • FutureTask同时实现了Runnable,Future接口。它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值

1.3、使用Callable来使用线程计算100以内的偶数的和

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//1、创建一个实现Callable的实现类
class Numbers implements Callable {
    //2、实现call方法,将此线程需要的操作声明在call()方法中
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}
public class TreadCabble {
    public static void main(String[] args) {
        //3、创建Callable接口的实现类的对象
        Numbers numbers = new Numbers();
        //4、将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask对象
        FutureTask futureTask = new FutureTask(numbers);
        //5、将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
        new Thread(futureTask).start();
        try {
            //get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值
            Object num = futureTask.get();
            System.out.println(num);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

2、新增方式二:使用线程池

背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。

思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建和销毁、实现重复利用。类似生活中的公共交通工具

好处:

提高影响速度(减少了创建新线程的时间)

降低资源消耗(重复利用线程池中线程,不需要每次都创建)

便于线程管理: corePoolSize:核心池的大小         maximunPoolSize:最大线程数  keepAliveTime:线程没有任                            务时醉倒保持多长时间后会终止

线程池相关API

JDK5.0起提供了线程池相关API:ExecutorService 和 Executors

ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor

image.png
Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池

image.png

 

发布了62 篇原创文章 · 获赞 21 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/lsy_666/article/details/105083526