并发编程系列之线程基础知识回顾

Posted smileNicky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程系列之线程基础知识回顾相关的知识,希望对你有一定的参考价值。

并发线程的知识是很重要而且比较杂的知识点,所以需要花不少时间用于整理。本博客整理线程的一些比较重要而且比较基础的知识点,帮忙读者入门,注意只是学习并发编程的一些基础点,要系统学习的是需要多看看书籍还是花不少时间整理的。本博客是在参加培训后做的笔记,仅供学习参考

问题1、使用多线程的目的是什么?

充分利用cpu资源,可以并发的处理任务

问题2、单核cpu不适合多线程?

单核cpu也是适合多线程的,单核的cpu系统中,一个进程中是允许有多个线程的。而且单线程在等待io时,cpu就空闲出来了

问题3、线程什么时候让出cpu?

  • 线程阻塞时,使用wait、await等待io时候
  • 线程sleep时,使用了sleep
  • 线程yield时候,使用了yield
  • 线程结束的情况

问题4、什么是线程?

线程是进程的一部分,可以理解为一条代码的执行流,完成一组代码的执行,这组代码往往被称之为一个任务

问题5、CPU是做什么工作的?

从执行代码角度,也可以说CPU就是执行代码的

问题6、如何正确stop线程

对于stop线程,读者可能会想能不能用Thread.stop?这种方法是绝对不允许的,在Oracle官网也对比进行了比较详细的说明,https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/doc-files/threadPrimitiveDeprecation.html

归纳起来就是这样的, 线程不安全 使用stop会释放所有持有的锁,会导致被保护的资源不一致,使得程序结构不确定

ok,然后如何正确的stop线程?

  • 1、使用volatile boolean变量来标记线程是否stop
private volatile stop = false;
public void doWork() {
     Thread t = new Thread(() -> {
         while (!stop) {
             // do someting
         }
     });
 }

public void doStop() {
    stop = true;
}
  • 2、使用线程的interrupt()方法
Thread.interrupt();
  • 3、对于blocking io的处理,使用interruptibleChannel来替代blocking io

问题7、创建线程的方法有多少种?

创建线程的方法从源码角度是只有一种的,也即new Thread,不过实现方式语法上来说就有很多种,比如实现Runnable接口,或者是通过继承Thread类实现,或者是通过Callable来实现,或者是通过线程池来创建等等,这种方法只是语法上的不同,要从源码角度来说就只有一种,所以面试时候可以列举这些方法,然后和面试官说从源码角度上来只有一种,详情可以参考我上篇博客并非编程系列之创建线程的方法有多少种?

问题8、线程有哪几个状态?

在idea里,用快捷键看一下Threa的状态,如图:

所以,线程的状态是有这几种的:

  • NEW(初始):也即新建一个线程对象,这个过程还没调用start方法
Thread t = new Thread(() -> {
   System.out.println(Thread.currentThread().getName());
});
System.out.println("创建线程后状态:" + t.getState());

创建线程后状态::NEW

  • RUNNABLE(运行):Java线程池中将(ready)就绪和(running)运行中两种状态统称为RUNNABLE,线程调用了start就会放在线程池中,处于就绪ready状态,等到分配到时间片后才变为运行runing状态
Thread t = new Thread(() -> {
   System.out.println(Thread.currentThread().getName());
});
t.start();
 System.out.println("Thread.start()之后的状态:" + t.getState());

Thread.start()之后的状态:RUNNABLE

  • BLOCKED(阻塞):表示线程阻塞于锁。线程抢不到锁就会出现这种状态
Thread t1 = new Thread(() -> {
    synchronized (ThreadStatusExample_Synchronized.class) {
        System.out.println("t1抢到锁");
    }
 });

 synchronized (ThreadStatusExample_Synchronized.class) {
     t1.start();
     Thread.sleep(1000L);
     System.out.println("t1抢不到锁时的状态:"+t1.getState());
 }

t1抢不到锁时的状态:BLOCKED
t1抢到锁

  • WAITING(等待):WAITING状态,线程进入等待状态
public static void main(String[] args) throws Throwable {

	Thread t1 = new Thread(() -> {
		LockSupport.park();
	});
	t1.start();
	Thread.sleep(2000L);	
	System.out.println("t1 被park后的状态:" + t1.getState());
	LockSupport.unpark(t1);
}

t1 被park后的状态:WAITING

  • TIMED_WAITING(超时等待):这种timed_awiting不同于waiting,可以在指定的时间后自行返回
private static volatile boolean running = true;

public static void main(String[] args) throws Throwable{
    Thread t = new Thread(() -> {
        while (running) {}
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    t.start();
    // volatile boolean标志的变量设置为false,让子线程退出循环
    running = false;

    Thread.sleep(1000L);
    System.out.println("Threa.sleep之后的状态:" + t.getState());
}

Threa.sleep之后的状态:TERMINATED

  • TREMINATED(终止):这个状态表示线程已经执行完成

这种情况,可以用Thread.sleep,等到线程执行完成就会打印出来

问题9、线程状态的转换

问题10、Runnable和Callable对象是线程?

Thread才是线程对象,Runable和Callable可以理解为线程任务,需要开发者自己去实现接口

以上是关于并发编程系列之线程基础知识回顾的主要内容,如果未能解决你的问题,请参考以下文章

Java并发编程系列之二线程基础

掌握系列之并发编程-1.并发基础

重点知识学习(8.1)--[回顾线程知识,初探并发编程知识]

并发编程系列之如何正确使用线程池?

并发编程系列之如何正确使用线程池?

并发编程之协程