并发编程之——线程基础

末蓝、 2022-05-17 08:19 336阅读 0赞

一、线程和进程

进程:程序运行资源分配的最小单位,进程内部有多个线程,会共享这个进程的资源。

线程:CPU调度的最小单位,必须依赖进程而存在,线程之间共享进程的资源。

二、线程的开启方式

1.继承Thread

  1. public class UserThread extends Thread {
  2. @Override
  3. public void run() {
  4. System.out.println("通过继承Thread类开启新线程!");
  5. }
  6. }

2.实现Runnable接口

  1. public class UseRunnable implements Runnable {
  2. @Override
  3. public void run() {
  4. System.out.println("通过实现Runnable接口开启新线程!");
  5. }
  6. }

3.实现Callable接口

  1. public class UseCallable implements Callable<String> {
  2. @Override
  3. public String call() throws Exception {
  4. System.out.println("通过实现Callable接口开启新线程!");
  5. return "通过实现Callable接口开启新线程!";
  6. }
  7. }

测试代码:

  1. public static void main(String[] args) throws ExecutionException, InterruptedException {
  2. //1.使用继承Thread的方式开启新线程
  3. Thread thread = new UserThread();
  4. thread.start();
  5. //2.使用实现Runnable接口的方式开启新线程
  6. Thread runnable = new Thread(new UseRunnable());
  7. runnable.start();
  8. //3.使用实现Callable接口的方式开启新线程
  9. //包装Callable为Runnable的类,因为Thread不接受直接传递Callable,FutureTask也为Runnable的子类
  10. //FutureTask会在Runnable的run方法中调用Callable的call方法,从而达到开启新线程的效果。
  11. FutureTask<String> futureTask = new FutureTask<>(new UseCallable());
  12. Thread callable = new Thread(futureTask);
  13. callable.start();
  14. //通过FutureTask的get方法拿到返回值,如果Callable没执行完没获取到返回值,会阻塞。
  15. String result = futureTask.get();
  16. System.out.println(result);
  17. }

注意:使用实现Callable接口的方式,需要使用FutureTask包装Callable,再传入至Thread中。

三、线程有关的API

Thread方法:

  1. start():开启并运行一个新的线程。
  2. getId():返回该线程的id
  3. getName():返回该线程的名字
  4. getPriority():返回该线程的优先级
  5. getState():返回该线程的状态
  6. isAlive():检测该线程是否还活着
  7. isDaemon():检测该线程是否为守护线程
  8. join():在A线程中调用B线程的join()方法,则为A线程等待B线程执行完后再执行,即A线程阻塞,直到B线程执行完。
  9. Thread.yield():静态方法,使当前线程放弃cpu的执行权重新进入就绪状态,注意该方法持有的锁是不释放的。
  10. Thread.sleep(long millis):静态方法,使当前线程睡眠,单位毫秒,注意该方法持有的锁是不释放的。
  11. interrupt():将该线程中断(实际并不会中断,只是将中断标志设置为true),如果线程正处在sleep(),join(),wait()方法中时(也就是阻塞时)调用该方法,该方法会抛出异常。
  12. isInterrupted():检测该线程是否已经中断,返回truefalse
  13. Thread.interrupted():静态方法,检测当前线程是否已经中断,返回truefalse
  14. Thread.currentThread():返回对当前正在运行的线程。

Object方法:

  1. wait():使当前持有锁的线程进入等待状态,注意该方法会释放持有的锁。
  2. wait(long):使当前持有锁的线程进入等待状态,并设置超时时间,超时后会自动唤醒,注意该方法会释放持有的锁。
  3. notify():随机唤醒一个通过该对象加锁并且处于等待中的线程。
  4. notifyAll():唤醒所有通过该对象加锁并且等待中的线程。

四、线程的生命周期

1.新建:就是new出来的线程

2.就绪:调用线程的start()方法后,这时线程处于等待CPU分配资源阶段,谁分配到CPU资源谁先开始执行。

3.运行:就绪线程被调度并获得CPU资源时,则进入运行状态,运行run方法中的代码。

4.阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如调用了该线程的sleep()、wait()或调用其它线程的join(),使当前线程进入了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify()、notifyAll()方法或等待。注意,唤醒的线程不会立刻执行run(),它们要再次等待CPU分配资源后再次进入运行状态。

5.销毁:如果线程正常执行完毕或抛出异常导致结束,那么线程就要被销毁,释放资源。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3OTE0NTg4_size_16_color_FFFFFF_t_70

五、synchronized内置锁

synchronized为对象锁,锁的是对象的实例,常说的类锁其实也是对象锁,锁的是类的class对象,每个类的class对象在虚拟机中只有一个,所以类锁也只有一个。

在静态方法定义中加锁,则是为对该类的class对象加锁,在普通方法定义中加锁,则是为当前this对象进行加锁。

六、ThreadLocal

线程变量,可以理解为是个map,类型 Map(实际上Key是ThreadLocal,是对Thread的包装),适合存储小对象,不会有线程安全问题,ThreadLocal的作用是为了能够在当前线程中有属于自己的变量。

发表评论

表情:
评论列表 (有 0 条评论,336人围观)

还没有评论,来说两句吧...

相关阅读

    相关 并发编程-Java线基础

    基础概念 程序、进程和线程 > 程序是指指令和数据的集合。 > > 指令在CPU上执行。数据需要被加载到内存中。指令执行用到数据时,需要从内存中读取并拷贝对应数据

    相关 并发编程线线

    1. 线程 线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。 线程是调度CPU资源的最小单位,线程模型分为K

    相关 并发编程——线基础

    一、线程和进程   进程:程序运行资源分配的最小单位,进程内部有多个线程,会共享这个进程的资源。 线程:CPU调度的最小单位,必须依赖进程而存在,线程之间共享进程的资

    相关 并发编程线

    为什么使用线程池 有时候,系统需要处理非常多的执行时间很短的请求,如果每一个请求都开启一个新线程的话,系统就要不断的进行线程的创建和销毁,有时花在创建和销毁线程上的时间会