热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

线程介绍,常用方法,生命周期,线程守护,线程同步机制,互斥锁,线程死锁相关概念

一、引入概念程序:是为完成特定任务、用某种语言编写的一组指令的集合。简单的说:就是我们写的代码进程:1、进程是指运行中的程序2、进程是程序的一次执行过程,或是正在运行的一个程序,是

一、引入概念

程序:是为完成特定任务、用某种语言编写的一组指令的集合。简单的说:就是我们写的代码

进程:

1、进程是指运行中的程序

2、进程是程序的一次执行过程,或是正在运行的一个程序,是动态过程:有它自身产生,存在和消亡的过程。

线程:

1.线程由进程创建的,是进程的一个实体

2.一个进程可以拥有多个线程,

单线程和多线程:

单线程:同一个时刻,只允许执行一个线程

多线程:同一时刻,可以执行多个线程

并发和并行:

 

 

 二、线程的继承实现图;(自定义线程可以继承Thread也可以直接实现Rubable)

(1)继承Thread实现一个简单的线程

public class Thread01 {
public static void main(String[] args) {
cat cat = new cat();

      cat.run();//run只是在cat中的一个方法,当调用时,并不会重新开启一个线程。会在main中按照顺序执行
      cat.start();//启动线程,启动之后run方法开始运行,并不会对main方法造成任何影响。

} }
class cat extends Thread{ @Override public void run() { int runtime = 0; while (runtime<8) { try { System.out.println("喵喵,我是小猫咪!"); runtime++; Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }

线程的结构

 

可以在程序运行时(进程开始的时候:在终端利用Jconsole查看当前进程中的线程)

 

 

 注意:

在进程中,如果主线程停止了,子线程还没结束,并不会结束进程。

(2)实现一个Runnabled的接口,实现一个多线程的类

public class Thread02 {
public static void main(String[] args) {
dog dog = new dog();
//dog.start();

Thread thread = new Thread(dog);
thread.start();
}
}
class dog implements Runnable{
@Override
public void run() {
int timesize = 0;
while (timesize<10) {
try {
System.out.println("hi! here is a dog!!!");
timesize++;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

注意:由于没有继承Thread类,所以在main中无法调用start方法启动线程,Runnable中只有一个run方法,所以需要重新定义一个新的线程,再将实现类dog放进去;

(3)线程的的基本使用

<1>线程如何理解:

 

 

 

 

(4)线程终止

基本说明:

1.当线程完成任务后,会自动退出。
2.还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式

(利用一个loop来通知线程结束)

public class Thread02 {
public static void main(String[] args) throws InterruptedException {
dog dog = new dog();
//dog.start();
Thread thread = new Thread(dog);
thread.start();
Thread.sleep(10*1000);
dog.setLoop(false);
}
}
class dog implements Runnable{
private boolean loop = true;
public void setLoop(boolean loop) {
this.loop = loop;
}
@Override
public void run() {
int timesize = 0;
while (loop) {
try {
System.out.println("hi! here is a dog!!!");
timesize++;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

(5)线程常用方法

1).setName //设置线程名称,使之与参数name相同

2).getName//返回该线程的名称
3). start//使该线程开始执行;Java虚拟机底层调用该线程的startO方法

4). run 1/调用线程对象run 方法;
5).setPriority //更改线程的优先级

6). getPriority //获取线程的优先级
7).sleep1/在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
8). interrupt 1/中断线程

9)yield:线程的礼让。让出cpu,让其他线程执行,但礼让的时间不确定,所以也不一定礼让成功

10).join: 线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务

 代码实例:

public class ThreadMothed {
public static void main(String[] args) throws InterruptedException {
T t = new T();
t.start();//启动线程
for (int i = 0; i <10; i++) {//进行主线程的代码运行
Thread.sleep(1000);
System.out.println("here is main!!"+i);
if (i == 3){
System.out.println("开始插队!!");
t.join();//让T插队,插队之后t线程将运行完毕退出再进入主程序
System.out.println("插队完成!!");
}
}
}
}
class T extends Thread{
@Override
public void run() {
int i = 0;
while (i<10){
try {
for (int j = 0; j <10; j++) {
Thread.sleep(1000);
System.out.println("hello test let`s go!!"+ j);
i++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

 11)用户线程和守护线程

1.用户线程:也叫工作线程,当线程的任务执行完或通知方式结束
2.守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束

3.常见的守护线程:垃圾回收机制

public class ThreadMothed01 {
public static void main(String[] args) throws InterruptedException {
T1 t1 = new T1();
Thread thread = new Thread(t1);
thread.setDaemon(true);//设置线程为守护线程
thread.start();
for (int i = 0; i <5; i++) {
System.out.println("test deamon!!!");
Thread.sleep(1000);
}
}
}
class T1 implements Runnable{
@Override
public void run() {
int i = 0;
// while (i <10) {
while (true) {//测试守护线程
for (int j = 0; j <10; j++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("test!!!" + j);
i++;
}
}
}
}

 

二、线程的生命周期

1、在JDK中Thread.State枚举表示了线程的几种状态

 

 

线程状态图

 

 三、线程同步机制(Synchronized)

线程同步机制:

1.在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技
术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。
2.也可以这里理解:线程同步,即当有一个线程在对内存进行操作时,其他线程都不
可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作.

同步具体方法:

 

 四、互斥锁

基本介绍:

1. Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。
2.每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
3.关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问
4.同步的局限性:导致程序的执行效率要降低
5.同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)

6.同步方法(静态的)的锁为当前类本身。

public class selltickets {
public static void main(String[] args) {
// Tickets tickets = new Tickets();
// Tickets tickets1 = new Tickets();
// Tickets tickets2 = new Tickets();
// tickets.start();

//定义三个新线程,开始进行线程同步测试,线程处理的对象需要是同一个对象
//不然不会体现出线程同步,线程锁的作用
Tickets tickets = new Tickets();
new Thread(tickets).start();
new Thread(tickets).start();
new Thread(tickets).start();
}
}
class Tickets extends Thread{
//class Tickets implements Runnable{
private int ticket = 100;
private boolean loop = true;
@Override
public void run() {
while (loop){
loop=sell();
}
}
private synchronized boolean sell(){
if (ticket<=0){
System.out.println("票已全部售出。。。");
return false;
}
if (ticket>0){
System.out.println(Thread.currentThread().getName() + "-售出一张票-剩余的票数"+(--ticket));
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return true;
}
}

 

注意事项和细节:

1.同步方法如果没有使用static修饰:默认锁对象为this

2.如果方法使用static修饰,默认锁对象:当前类.class
3.实现的落地步骤:
需要先分析上锁的代码

选择同步代码块或同步方法
要求多个线程的锁对象为同一个即可!

 五、线程死锁

简介:多个线程都占用了对方的锁资源,但不肯相让,导致了死锁,在编程是一定要避免死锁的发生。

(1)使用继承方式Thread 体现死锁

public class DeadLock {
public static void main(String[] args) {
Lock lock = new Lock(true);//传参true获取o1对象
lock.setName("true");//设置线程名称
Lock lock1 = new Lock(false);//传参true获取o2对象
lock1.setName("false");
//开始新的进程
lock.start();
lock1.start();
}
}
class Lock extends Thread {
static Object o1 = new Object();
static Object o2 = new Object();
private boolean loop;
public Lock(boolean loop) {
this.loop = loop;
}
@Override
public void run() {
if (loop){
synchronized (o1){
System.out.println(Thread.currentThread().getName()+"进入正确的o1,等待o2");
synchronized (o2){
System.out.println("拿到o2,o1执行完成");
}
}
}else{
synchronized (o2){
System.out.println(Thread.currentThread().getName()+"进入错误的o1,等待o2");
synchronized (o1){
System.out.println("拿到o2,o1执行完成");
}
}
}
}
}

使用实现Runnable 的方式体现死锁

public class DeadLock {
public static void main(String[] args) {
Lock lock = new Lock(true);
Thread thread = new Thread(lock);
thread.setName("A");
Lock lock1 = new Lock(false);
Thread thread1 = new Thread(lock1);
thread1.setName("B");
thread.start();
thread1.start();
}
}
class Lock implements Runnable {
static Object o1 = new Object();
static Object o2 = new Object();
private boolean loop;
public Lock(boolean loop) {
this.loop = loop;
}
@Override
public void run() {
if (loop){
synchronized (o1){
System.out.println(Thread.currentThread().getName()+"进入正确的o1,等待o2");
synchronized (o2){
System.out.println("拿到o2,o1执行完成");
}
}
}else{
synchronized (o2){
System.out.println(Thread.currentThread().getName()+"进入错误的o1,等待o2");
synchronized (o1){
System.out.println("拿到o2,o1执行完成");
}
}
}
}
}

六、释放锁

释放锁的情况:

1.当前线程的同步方法、同步代码块执行结束
案例:上厕所,完事出来
2.当前线程在同步代码块、同步方法中遇到break、return.
案例:没有正常的完事,经理叫他修改bug,不得已出来
3.当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束
案例:没有正常的完事,发现忘带纸,不得已出来
4.当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释
放锁。
案例:没有正常完事,觉得需要酝酿下,所以出来等会再进去

不会释放锁的情况:

1.线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方
法暂停当前线程的执行,不会释放锁
案例:上厕所,太困了,在坑位上眯了一会
2.线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,
该线程不会释放锁。
提示:应尽量避免使用suspend()和resume()来控制线程,方法不再推荐使用

 



推荐阅读
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了在Java中gt、gtgt、gtgtgt和lt之间的区别。通过解释符号的含义和使用例子,帮助读者理解这些符号在二进制表示和移位操作中的作用。同时,文章还提到了负数的补码表示和移位操作的限制。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
author-avatar
宫金丹865
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有