Java多线程的一些基础

前言

多线程我想大家应该都比较了解,发明线程的原因就是为了能更好的利用CPU的资源,如果主线程因为某种原因阻塞,那么相应的进程也让出了CPU资源并且暂停执行,那么如果一个进程当中有多个线程的话,CPU的利用效率提高很多。那我们来说一说Java中的多线程。

线程的生命周期

  • 新建:比如我们new出了一个Thread对象
  • 就绪:我们调用start方法后,进入就绪状态,也就是已经进入就绪队列等待得到CPU资源
  • 运行:线程获得了CPU资源正在执行任务
  • 死亡:线程执行完毕或被其他线程杀死,正常运行Run方法终止或者调用stop方法终止
  • 阻塞:某种原因让正在运行的线程让出自己的CPU并暂停执行,比如sleep,wait方法(调用notify回到就绪状态),被另一个线程阻塞(调用suspend方法,调用resume方法恢复)

结束线程的原理:让run方法结束,一般run方法中定义循环结构,只要控制住循环即可,可以使用标志位

线程的控制

开启线程:线程对象调用start方法后(start方法只能被调用一次)

暂停线程:线程对象调用sleep方法,让线程休眠指定的秒数

终止线程:对于使用stop方法和interrupt方法来终止线程是不安全的,正确做法是设置一个boolean类型的标志位

还有两个线程控制的方法:

join方法:使线程间的并行变为串行,通俗的来说,此线程都执行完毕后才会执行主线程或者其他线程,如果join传参了,那就是等待指定的秒数后再执行主线程或者其他线程

yield方法:相当于礼让的意思,在子线程中不使用yield方法,假设主线程得到CPU资源的概率为40%,使用了yeild方法后,主线程得到CPU资源的概率为90%,大概就是这么个意思

线程同步

当有一个线程对内存进行操作的时候,其他的线程都不能对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作。很经典的一个问题就是多个线程卖票的问题,如果不去考虑线程的同步问题,那么卖票可能会出很严重的问题

解决办法

通过锁机制:每当有线程进入某方法中执行代码时,给某个对象加一个标记,当线程执行完毕的时候,将这个标记清除。其他线程想要进入该方法前要检查一下这个标记,如果这个标记存在,就等待,否则就进入方法中执行代码

ReentrantLock

如果有多个线程都要调用getApple方法,就会执行lock.lock()方法,进行一个锁的实现,简单的使用方法:

public class XXX {
   private final ReentrantLock lock = new ReentrantLock();
   // ...
 
   public void getApple() {
     lock.lock();  // 当前执行代码的线程尝试获取锁对象,如果当前锁对象被其他线程获取,则陷入阻塞状态
                   // 保证了在同一时刻只能有一个线程进入 try 代码块中执行代码,即实现线程同步
     try {
       // do something...
     } catch (Exception e) {
     } finally {
       lock.unlock() // 最后一定记得释放锁对象,不然可能导致死锁
     }
   }
 }
  • ReentrantLock和synchronized的区别
ReentrantLock在获取锁失败之后不会进入阻塞状态,而是会返回获取锁的结果,那么在线程获取锁失败的时候让这个线程去干别的事情。
  • wait和sleep的区别

1、wait()、notify()、notifyAll()三个方法都是Object的方法,sleep是Thread的方法

2、wait()会释放锁,sleep不会释放锁

3、wait()只能在同步控制方法或同步控制块中使用,sleep可以在任何地方使用

4、wait()不需要捕获异常,sleep需要捕获异常



猜你喜欢

转载自blog.csdn.net/pengbo6665631/article/details/80808742