Java多线程详解

   欢迎来到茶色岛的神秘岛屿,在这里你将收获Java多线程的奥秘

 活动地址:CSDN21天学习挑战赛

 ​学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您:
想系统/深入学习某技术知识点…
一个人摸索学习很难坚持,想组团高效学习…
想写博客但无从下手,急需写作干货注入能量…
热爱写作,愿意让自己成为更好的人…


欢迎参与CSDN学习挑战赛,成为更好的自己,请参考活动中各位优质专栏博主的免费高质量专栏资源(这部分优质资源是活动限时免费开放喔~),按照自身的学习领域和学习进度学习并记录自己的学习过程。您可以从以下3个方面任选其一着手(不强制),或者按照自己的理解发布专栏学习作品,参考如下:

前言

一、基本概念:程序、进程、线程

1.程序(program):

2.进程(process)

3.线程(thread)

二、线程的创建和使用

1.Thread类

2.API 中创建 线程的两种方式

三、线程的生命周期

四、线程的同步

1.问题的原因:

2. 解决办法:

3.具体实现方法:

4.同步机制中的锁

5.释放锁的操作

6.不会释放锁的操作

五、线程的通信

六、JDK5.0新增线程创建方式

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

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

总结

让天下没有难学的技术。



前言

Hello,大家好✋✋,我是茶色岛,一位已经在csdn呆了将近一年的博主,本篇文章将为大家讲解Java多线程,希望会对你们有所帮助,同时也希望可以收获大家的喜爱,点个关注,谢谢大家。

一、基本概念:程序、进程、线程

1.程序(program):

为完成特定任务、用某种语言编写的一组指令的集合。

即指一段静态的代码,静态对象

2.进程(process)

是程序的一次执行过程,或是正在运行的一个程序。

是一个动态的过程:有它自身的产生、存在和消亡的过程

3.线程(thread)

进程可进一步细化为线程,是一个程序内部的一条执行路径

  • 若一个进程同一时间 并行执行多个线程,就是支持多线程的
  • 一个Java应用程序java.exe,其实至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程。
  • 单核CPU,其实是一种假的多线程,如果是多核的话,才能更好的发挥多线程的效率
  • 并行与并发
     1.并行:多个CPU同时执行多个任务。比如:多个人同时做不同的事。
     2.并发:一个CPU(采用时间片)同时执行多个任务。比如:秒杀、多个人做同一件事

何时需要多线程

  • 程序需要同时执行两个或多个任务。
  • 程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。
  • 需要一些后台运行的程序时。

二、线程的创建和使用

1.Thread类

程序运行多个线程通过java.lang.Thread类来体现

  • 每个线程都是通过某个特定Thread对象的run()方法来完成操作的,经常把run()方法的主体称为线程体
  • 通过该Thread对象的start()方法来启动这个线程,而非直接调用run()

 构造器

  • Thread() :创建新的Thread对象
  • Thread(String threadname): :创建线程并指定线程实例名
  • Thread(Runnable target) :指定创建线程的目标对象,它实现了Runnable接口中的run方法
  • Thread(Runnable target, String name) :创建新的Thread对象

2.API 中创建 线程的两种方式

方式一: 继承Thread类
1) 定义子类继承Thread类。
2) 子类中重写Thread类中的run方法。
3) 创建Thread子类对象,即创建了线程对象。
4) 调用线程对象start方法:启动线程,调用run方法。

 方式二:实现Runnable 接口
1) 定义子类,实现Runnable接口。
2) 子类中重写Runnable接口中的run方法。
3) 通过Thread类含参构造器创建线程对象。
4) 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
5) 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。

Thread 类的有关方法

  • void start(): 启动线程,并执行对象的run()方法
  • run(): 线程在被调度时执行的操作
  • String getName(): 返回线程的名称
  • void setName(String name):设置该线程名称
  • static Thread currentThread(): 返回当前线程。在Thread子类中就
  • 是this,通常用于主线程和Runnable实现类
  • static void yield(): : 线程让步(暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程,若队列中没有同优先级的线程,忽略此方法)
  • join() : 当某个程序执行流中调用其他线程的 join() 方法时,调用线程将被阻塞,直到 join() 方法加入的 join 线程执行完为止(低优先级的线程也可以获得执行)
  • static void sleep(long millis) :(指定时间:毫秒)令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。抛出InterruptedException异常
  • stop(): 强制线程生命期结束,不推荐使用
  • boolean isAlive(): : 返回boolean,判断线程是否还活着

三、线程的生命周期

Java多线程详解_第1张图片

 

四、线程的同步

1.问题的原因:

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。

2. 解决办法:

对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以
参与执行。

3.具体实现方法:

1.使用Synchronized维持线程同步

1. 同步代码块 :
synchronized ( 对象){
// 需要被同步的代码;
}
2. synchronized 还可以放在方法声明中,表示 整个 方法为 同步方法 。
例如:
public synchronized void show (String name){
….
}

2.使用 Lock( 锁)维持线程同步
 

class A{
           private final ReentrantLock lock = new ReenTrantLock();
           public void m(){
                   lock.lock();
                   try{
                        // 保证线程安全的代码;
                       }
                   finally{
                            lock.unlock();
                           }
                     }
       }

synchronized 与 Lock 的对比

1.Lock是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized是
隐式锁,出了作用域自动释放
2. Lock只有代码块锁,synchronized有代码块锁和方法锁
3. 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有
更好的扩展性(提供更多的子类)

优先使用顺序:
Lock -> 同步代码块(已经进入了方法体,分配了相应资源) ->同步方法(在方法体之外)

4.同步机制中的锁

  •  必须确保使用同一个资源的 多个线程共用一把锁
  •  一个线程类中的所有静态方法共用同一把锁(类名.class),所有非静态方法共用同一把锁(this),同步代码块(指定需谨慎)

5.释放锁的操作

  • 当前线程的同步方法、同步代码块执行结束。
  • 当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
  • 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束。
  • 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁

6.不会释放锁的操作

  • 线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行
  • 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)。应尽量避免使用suspend()和resume()来控制线程

五、线程的通信

执行wait() 与 与 notify() 和 和 notifyAll()

  • 这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会java.lang.IllegalMonitorStateException异常。
  • 因为这三个方法必须有锁对象调用,而任意对象都可以作为synchronized的同步锁,因此这三个方法只能在Object类中声明。

wait() 方法

  • 在当前线程中调用方法: 对象名.wait()
  • 使当前线程进入等待(某对象)状态 ,直到另一线程对该对象发出 notify(或notifyAll) 为止。
  • 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
  • 调用此方法后,当前线程将释放对象监控权 ,然后进入等待
  • 在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行

notify()/notifyAll()

  • 在当前线程中调用方法: 对象名.notify()
  • 功能:唤醒等待该对象监控权的一个/所有线程。
  • 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)

六、JDK5.0新增线程创建方式

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

  • 相比run()方法,可以有返回值
  • 方法可以抛出异常
  • 支持泛型的返回值
  • 需要借助FutureTask类,比如获取返回结果

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

线程池相关API:ExecutorService 和 Executors

总结


  以上就是今天要讲的java线程,本文仅仅简单介绍了线程的基础知识。

长路漫漫,希望我们一起努力。

让天下没有难学的技术。

Java多线程详解_第2张图片

 

你可能感兴趣的:(JavaSE,java,算法,jvm)