java 多线程基础学习

短命女 2022-03-17 01:21 352阅读 0赞

一、线程概念

1、进程:程序运行资源分配的最小单位,每个进程都有自己独立的代码和数据空间,操作系统为进程分配各种资源。

2、线程:CPU调度的最小单位,也叫轻量级进程,每个线程都有各自的堆栈、计数器和局部变量等属性。

3、线程和进程关系:线程依赖于进程而存在,多个线程共享进程的内存空间。

异步和同步:

同步:在同一个线程中执行一段业务逻辑时,按顺序执行,在前面的结果没有返回时,后面的程序就不能往下执行,必须等待前一个结果返回时后面的才能往下执行。

异步:多线程是实现异步的一个手段,异步是当一个请求发送给被调用者,调用者可以不用等待结果返回而可以做其他的事情。

就像我们每天去到公司一样,先打开电脑,在电脑开机过程中可以去接点水喝,而不用等待电脑开机再去接水喝。

并发和并行:

并行:同一时刻可以处理事情的能力,比如一台四核的电脑,可以同时运行四个任务,我们就说这台电脑并行度是4

并发:在单位时间内可以处理的事情,主要还是看这台电脑时间分片的长短,如果这台电脑的时间分片为100ms,在1s内就可以处理10个任务,那么就说这台电脑的并发度是40。因为任务是在交替执行的,并发的任务就会让我们以为这些任务是同时执行的,其实还是顺序执行的。

二、线程的优势:

现如今服务器多采用多处理器,CPU的基本调度单位是线程,如果一个程序只有一个线程的话,那么就只能发挥一个CPU的作用,其他CPU的资源将会闲置,这在很大程度上浪费了CPU的资源,如果能够多个CPU同时发挥作用,在设计正确的情况下,可以通过提高CPU资源的利用率来提高系统的吞吐率。

三、线程状态

通过Thread.state 可以查看线程的状态:

NEW:新建状态。这种状态下线程还没有开始,也就是还没有调用start方法

RUNNABLE:可运行状态。这个状态下的线程可能处于执行阶段,但是也有可能在等待来自操作系统的其他资源,例如等待CPU为其分配时间片。ready和running在这两种状态在Java中统称为RUNNABLE,分开写是为了更好的理解

BLOCKED:阻塞状态。表示线程阻塞于锁

WAITING:等待状态。进入等待状态的线程需要其他线程做出一些特定动作,例如通知或中断

TIMED_WAITING:超时等待状态。该状态不同于WAITING状态,它可以在指定时间内自动返回。

TERMINATED:终止状态。表示当前线程已经执行结束

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NjU0ODQx_size_16_color_FFFFFF_t_70

t.start()之后并不代表线程已经启动,此时它只是在可运行池中,随时等待被CPU调度,一旦获取到CPU时间片才真正的出于可运行状态。

线程的优先级:

1、线程有1-10,10个优先级选择,最小优先级是1(MIN_PRIORITY),默认优先级5(NORM_PRIORITY),

最大优先级是10(MAX_PRIORITY)

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NjU0ODQx_size_16_color_FFFFFF_t_70 1

2、如果没有指定线程的优先级,默认是普通优先级,也就是NORM_PRIORITY

3、通过t.setPriority(int newPriority)为线程设定优先级

注意:不要试图通过设定优先级来指定线程的启动顺序,优先级的设定只是说明这个线程在CPU调度时有更大的概率被选中,而且这种优先级设定有不确定性,在某些操作系统中可能优先级的设定并不起作用。

方法介绍:

1、join()方法:在线程A中调用B的join()方法,线程B将会先于线程A执行,线程A必须等待线程B执行完成才能执行,有点类似于插队。同时join()方法还有两个重载的带有时间的方法,join(long millis)、join(long millis, int nanos),它表示如果线程B没有在指定时间内完成,则返回。相当于给插队线程加了时间限制,超时自动返回。

2、yield():Thread的静态方法。当前线程让出CPU执行权,当前线程会从运行状态变为可运行状态,重新回到可运行线程池,但是他还是会可能被再次选中执行。

3、sleep(long millis):Thread的静态方法,使当前线程t休眠n毫秒,如果当前线程t持有锁,休眠期间不会释放锁,其他线程将无法获得锁,当其他线程调用t.interrupt()唤醒休眠线程。当到了休眠时间当前线程t会自动进入RUNNABLE状态。

4、wait():对象方法,使当前线程进入等待状态,它不会返回,除非我们调用t.notify()或者t.notifyAll()方法唤醒,唤醒之后将和其他线程竞争获得锁。调用wait()方法的前提是当前线程必须持有锁,否则会抛异常,在调用wait()方法之后会释放锁,让其他线程有机会获得锁。

sleep()和wait()的区别:

1、sleep()是Thread的静态方法,wait()是Object的方法。

2、当调用sleep()的线程获得锁时不会自动释放锁,调用wait()会释放锁。

3、sleep()方法需要其他线程调用当前线程的interrupt()方法或者时间过期才能唤醒,wait()方法需要调用t.notify()或者t.notifyAll()方法唤醒。

线程的中断:

如果线程执行完成或者抛出未处理的异常,线程就会终止。

线程中断的方法有stop()、resume()、suspend()和interrupt(),但是前三个已经废弃了,stop()会使线程不正确释放资源,resume()只是为了suspend()而存在,这两个方法会导致死锁。所以最后只剩下interrupt()了。

java线程是协作式的,意思就是当调用当前线程t的interrupt()时,当前线程t并不会立马终止,而是跟当前线程打个招呼,“兄弟,你死期到了,我跟你说一下,你爱死不死”,同时会把t的中断标志设置为true。当线程抛出InterruptedException时,线程中断标志将会清除,调用静态方法Thread.interrupted()可以判断线程是否中断,同时将中断标志将被清除并设置为false。

实例如下:

主函数

  1. public static void main(String[] args) throws InterruptedException {
  2. //创建两个线程
  3. InterruptThread interruptThread = new InterruptThread();
  4. interruptThread.setName("thread1");
  5. InterruptThread2 interruptThread2 = new InterruptThread2();
  6. interruptThread2.setName("thread2");
  7. //启动两个线程
  8. interruptThread.start();
  9. interruptThread2.start();
  10. //主线程休眠5秒 使两个线程充分运行
  11. TimeUnit.SECONDS.sleep(5);
  12. //中断InterruptThread
  13. interruptThread.interrupt();
  14. }

静态内部线程1:

  1. private static class InterruptThread extends Thread{
  2. @Override
  3. public void run() {
  4. interrupt(); //将中断标志设置为true
  5. System.err.println("before thread1 interrupt status:"+isInterrupted());
  6. while (true){
  7. try {
  8. sleep(6000);
  9. } catch (InterruptedException e) {
  10. System.err.println("exception thread1 interrupt status:"+isInterrupted());
  11. }
  12. }
  13. }
  14. }

静态内部线程2:

  1. private static class InterruptThread2 extends Thread{
  2. @Override
  3. public void run() {
  4. long start = System.currentTimeMillis();
  5. while (true){
  6. if (System.currentTimeMillis() - start > 2000){
  7. interrupt(); //将中断标志设置为true
  8. System.out.println("before thread2 interrupt status:"+isInterrupted());
  9. break;
  10. }
  11. }
  12. Thread.interrupted(); //清除中断标志,置为false
  13. System.out.println("after thread2 interrupt status:"+isInterrupted());
  14. }
  15. }

1、在InterruptThread 中先把中断标志设置为true,并打印是否中断,在主线程中再次将处于休眠状态中的InterruptThread 再次中断,此时会抛出异常,再次打印是否中断。在这个类中我们要证明的是,抛出InterruptedException 线程中断标志会被清除。

2、在InterruptThread2 中我们让InterruptThread2 正常运行2s,并在循环中将中断标志置为true,正常退出循环时,调用Thread.interrupted(); 清除中断标志,并打印是否中断。在这个类中我们要证明调用当前线程Thread.interrupted();会将中断标志清除。

在这两个类中证明了,java线程中断是协作式的,将中断标志置为true并不会立马就中断线程。

打印结果:

before thread1 interrupt status:true
exception thread1 interrupt status:false
before thread2 interrupt status:true
after thread2 interrupt status:false
exception thread1 interrupt status:false

四、创建线程

创建线程有三种方法:

1、继承Thread类

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NjU0ODQx_size_16_color_FFFFFF_t_70 2

2、实现Runable接口

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NjU0ODQx_size_16_color_FFFFFF_t_70 3

3、实现Callable接口

Callable是可以获取到返回值, 但是只能通过线程池来调用,它返回的是一个Future对象f,通过f.get()就能获取到结果。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NjU0ODQx_size_16_color_FFFFFF_t_70 4

线程池的介绍请看https://blog.csdn.net/qq_39654841/article/details/83244877

发表评论

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

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

相关阅读

    相关 java线基础学习归纳总结

    一、基本概念: 1.1、什么是进程 进程是资源分配的基本单位,是程序执行的一个实例。 程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入到进程就绪队列中

    相关 java 线基础学习

    一、线程概念  1、进程:程序运行资源分配的最小单位,每个进程都有自己独立的代码和数据空间,操作系统为进程分配各种资源。  2、线程:CPU调度的最小单位,也叫轻量级进程,