ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线程的初步学习

2021-10-16 22:00:08  阅读:130  来源: 互联网

标签:学习 对象 创建 ReentrantLock 初步 死锁 线程 方法


线程是操作系统中能够进行运算调度的最小单位,一个进程中最少拥有一个线程,进程中的任务都在线程中运行

如何创建线程:

  1. 继承 Thread 类,使用/重写 run() 方法
  2. 实现 Runnable 接口,重写 run() 方法
  3. 通过 Callable和 Future 创建线程

每次创建一个新的线程对象,他们都会有属于自己的 PC 寄存器,Java虚拟机栈,本地方法栈。堆和方法区则是所有线程共享

 

线程分为串行和并行两种。串行就是一条线程一条线程顺序执行;并行就是两条及两条以上线程同时运行。

  在单核 CPU 中,一次只能运行一条线程,单核的线程并行实际上是 CPU 在快速切换运行线程以实现的伪并行

线程运行状态分为以下几种:

  1. NEW (创建线程对象)
  2. Runnable (正在运行状态)
  3. Bloackd (阻塞状态)  //等待对象的内部锁
  4. Waitting (等待状态)  //等待其他线程  以下方法会造成当前状态: 
    1. 无超时值的 Thread.join() 方法
    2. 无超时值的 Obj.wait() 方法
  5. Time_Watting (定时等待状态)  //有时间限制的等待其他线程
    1. Thread.sleep()
    2. 有超时值的 Thread.join() 方法
    3. 有超时值的 Obj.wait() 方法
  6. Date

线程安全问题:

  当多线程同时访问一块内存并涉及到读写操作时,便有可能引发数据混乱,就可能会引发线程安全问题。如果需要解决线程安全问题一般使用同步技术

线程同步:一个线程在对一块内存进行操作时,其他线程都不可以对这块内存地址进行操作,直到该线程完成操作, 其他线程才能对这块内存地址进行操作。

  同步方式:  //Java的每个对象都有属于自己的内部锁

  1. 同步方法
    • 简单来说就是被 synchronized 关键字修饰的方法,但是他不能修饰构造方法。修饰实例方法时,即锁住了整个方法,在调用该方法前,需要获取该对象的内置锁,不然就会处于堵塞状态。
    • synchronized 也可以修饰静态方法,这样在调用时它就锁住了整个类,需要获取类对象的内置锁     //每个类都有属于自己的独一份的类对象
  1. 同步代码块
    • 简单来说就是被 synchronized 修饰的代码块,它会单独锁住一块代码,因为同步是一种高开销的操作,所以通常没必要锁方法,锁部分代码即可
  2. 可重入锁
    • 在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。可重入锁(ReentrantLock)就是实现了 Lock 接口的锁,这个锁具有和同步方法/代码块一样的一些基本功能并将其扩展
    • 基本方法 ReentrantLock() ReentrantLock.lock() ReentrantLock.tryLock() ReentrantLock.unlock()  ReentrantLock.isLocked  分别是创建对象,获取锁,尝试获取锁,释放锁,查看锁是否被持有

线程通信

  一条线程的运行需要另一条线程的参与,这样叫做线程之间的通信

  线程之间的通信可以使用 wait,notify / notifyAll 实现

实现过程:

  对象 A 调用对象 O 的 wait 方法进入等待状态,线程 B 调用对象 O 的 notify / notifyAll 方法通知对象 A 可以运行,对象 A 收到通知后退出等待状态进入可运行状态执行后续代码

  • 在执行 wait 方法前必须获取对象的内置锁,执行方法后会使当前线程进入堵塞状态并释放当前锁。
  • 执行 notify / All 方法后,当前线程不会马上释放对象锁,而是需要 notify / All 所在的线程将程序执行完毕(退出 synchronized 代码块/方法),当前线程才会释放锁。

死锁

  两条及两条以上线程互相堵塞的现象,称为死锁。死锁的产生有四个条件:

  1. 互斥:一段时间内一块资源仅为一个进程所有
  2. 不剥夺:一块资源未使用完毕不能被其他线程强制夺走
  3. 请求和保持:进程提出获取新资源,但是新资源被其他进程所有,而自己已获得的资源也保持不放
  4. 循环等待:存在一个循环闭环,链中每一个进程所获取的资源为下一个进程所请求

破环死锁:

互斥条件不可破坏,不剥夺条件破坏代价大

只需允许进程使用完一块资源便释放掉就可破坏死锁。另一种方法就是破坏循环链,对各进程访问资源的顺序做一个规定即可

线程池

由于常规线程执行完任务后就会结束生命周期,而频繁创建关闭线程会造成大量内存开销,为了优化这种情况,便引入了线程池的概念

线程池由工作线程组成,工作线程与普通线程不同,工作线程可以执行多个任务,如果一条工作线程被分配到多个任务,那么它会将这多个任务分配到队列中,然后顺序执行

JDK5 提供了一个 Executors 工厂类来生产线程池,方法如下(个别列举)

public static ExecutorService newFixedThreadPool(int nThreads)

public static ExecutorService newSingleThreadExecutor()

public static ExecutorService newCachedThreadPool()

可以通过以上方法创建线程池对象,控制创建几个线程对象。可以控制 Runnable / Callable 对象代表的线程

<T> Future<T> submit(Callable<T> task);    //创建线程对象

<T> Future<T> submit(Runnable task, T result);    //创建线程对象

Future<?> submit(Runnable task);    //创建线程对象

void shutdown();  //结束线程池

标签:学习,对象,创建,ReentrantLock,初步,死锁,线程,方法
来源: https://www.cnblogs.com/chensang21930/p/15415450.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有