Java知识点02:Java线程

一、创建线程的方式
1、继承Thread类
2、实现Runnable接口
3、使用Callable和Future创建线程
4、基于线程池的方式

  • 第一种方式:继承Thread类,重写run()方法,调用start()方法开启线程(start()方法是一个 native 方法,它将启动一个新线
    程,并执行 run()方法)
//第一种方式:继承Thread类
public class MyThread01 extends Thread {
    @Override
    public void run() {
        System.out.println("MyThread01 is running!");
    }

    public static void main(String[] args) {
        MyThread01 myThread01 = new MyThread01();
        myThread01.start();
    }
}
  • 第二种方式:实现Runnable接口,重写run()方法,在执行线程的时候放入runnable的实例对象,实际上Thread类也是继承了Runna接口

在这里插入图片描述

//第二种方式:继承Runnable接口
public class MyThread02 implements Runnable {

    @Override
    public void run() {
        System.out.println("MyThread02 is running!");
    }

    public static void main(String[] args) {
        //实例化线程
        MyThread02 myThread02 = new MyThread02();
        //调用start方法的时候,放入实例化对象
        new Thread(myThread02).start();
    }
}
  • 第三种方式:使用Callable和Future创建线程
//创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
// 创建多个有返回值的任务
List<Future> list = new ArrayList<Future>();
for (int i = 0; i < taskSize; i++) {
Callable c = new MyCallable(i + " ");
// 执行任务并获取 Future 对象
Future f = pool.submit(c);
list.add(f);
}
// 关闭线程池
pool.shutdown();
// 获取所有并发任务的运行结果
for (Future f : list) {
// 从 Future 对象上获取任务的返回值,并输出到控制台
System.out.println("res:" + f.get().toString());
}

或者是实现Callable接口,主要就是四步:创建执行服务、提交执行、获取结果、关闭服务

//第三种方式:重写Callable
public class TestCallable implements Callable<Boolean> {

    @Override
    public Boolean call() throws Exception {
        for (int i=0;i<10;i++){
            System.out.println("======"+i);
        }
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable t1 = new TestCallable();
        //创建执行服务
        ExecutorService ser = Executors.newFixedThreadPool(1);
        //提交执行
        Future<Boolean> r1 = ser.submit(t1);
        //获取结果
        boolean res1 = r1.get();

        System.out.println(res1);

        //关闭服务
        ser.shutdown();
    }
}
  • 第四种:基于线程池创建

线程池的顶级接口为:Executor,真正的接口为:ExecutorService

四种线程池:

newCachedThreadPool:创建一个可根据需要创建新线程的线程池,在以前构造的线程可用时将重用这些线程。调用execute将重用以前构造的线程(如果线程可用)。如果线程不可用,则创建一个新线程并添加到池中。终止并从缓存中移除已有60秒未被使用的线程。

newFixedThreadPool:创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。

newScheduledThreadPool:创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。

newSingleThreadExecutor:单例线程,任意时间内只能有一个线程,这个线程池可以在线程死后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去。

二、线程状态
新建状态、就绪状态、运行状态、阻塞状态、死亡状态

  • 第一种,新建状态

当程序使用new关键字创建了一个线程之后,该线程就处于新建状态

  • 第二种,就绪状态

当线程对象调用了start方法之后,该线程就处于就绪状态,JVM会为其创建方法调用栈和程序计数器,等待调度运行。

  • 第三种,运行状态

当处于就绪状态的线程获得了CPU,开始执行run()方法的线程知兴替,该线程就进入了运行状态。

  • 第四种,阻塞状态

阻塞状态指线程停止运行,释放出CPU的使用权。

阻塞分为以下三种情况:

①、等待阻塞:运行中的线程执行o.wait()方法,JVM会把该线程放入等待队列中。

②、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。

③、其他阻塞:执行sleep()方法、o.join()等方法时,当等待超时之后,线程重新转入可运行(runnable)状态。

  • 第五种,死亡状态,会用以下三种方式结束线程。

①、线程正常结束:run()方法或call()方法执行完成

②、线程异常结束:线程抛出一个未捕获的Exception或Error

③、调用stop()方法:该方法容易导致死锁,造成线程不安全

在这里插入图片描述

三、扩充知识

1、sleep()和wait()的区别

  • ①、sleep()方法属于Thread类;而wait()方法属于Object类。

  • ②、sleep()方法会让出CPU给其他线程,但是它的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态。

  • ③、调用sleep()方法的过程中,线程不会释放对象锁。

  • ④、调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池。

2、start()和run()的区别

  • ①、start()方法来启动线程,真正实现了多线程运行;此时无需等待run()方法体代码执行完毕,可以直接继续执行下面的代码。

  • ②、通过调用Thread类的start()方法来启动一个线程,这时此线程就是处于就绪状态的,并没有运行。

  • ③、run()方法称为线程体,它包含了只要执行的线程的内容,线程就进入了运行状态,开始运行run()方法当中的代码。

  • ④、run()方法运行结束,此线程终止,然后CPU再调度其他的线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值