一、基本概念:程序,进程,线程
1.程序:是为=完成特定任务,用某种语言编写的一组指令的集合=,即指一段静态的代码,静态对象
2.进程:是=程序的一次执行过程,或是正在运行的一个程序=,是一个动态的过程:有它自身的产生,存在和消亡的过程
3.线程:进程可进一步细化为线程,=是一个程序内部的一条执行路径=
若一个进程同一时间并行执行多个线程,就是支持多线程的
线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计算器,线程切换的开销小
一个线程中的多个线程共享相同的内存单元/内存地址空间->它们从同一堆中分配对象,可以访问相同的变量和对象,这就使得线程间通信更简便,高效。但多个线程操作共享的资源可能就会带来安全的隐患
4.并行与并发
并行:=多个cpu同时执行多个任务,比如:多个人同时做不同的事=
并发:=一个cpu(采用时间片)同时执行多个任务。=
5.一个线程对应的是一个栈内存
栈内存是一个连续的空间
二、线程的创建和使用
1.创建方式一
创建一个继承Thread类的子类
重写Thread类的run方法—>将此线程执行得到操作声明在run()方法中
创建Thread类的子类对象
通过此对象调用start()
问题一:我们不能通过直接调用run()的方式启动线程
问题二:一个线程只能调用一次start()方法,否则报运行异常
2.Thread中的常用方法
Start():启动当前线程,调用当前的线程的run()
run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
=currentThread:静态方法,返回当前代码的线程=
=getName():获取当前的线程的名字=
=setName():设置当前线程的名字=
yieid():释放当前cpu的执行权
=join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束状态=
Stop():已经过时,当执行此方法时,强制结束当前线程
=sleep():让当前线程”睡眠”指定的millitime毫秒。在指定的milltime毫秒时间内,当前线程是阻塞状态=
JsAlive():判断当前线程是否存活
3.线程的优先级别
(1).MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5–>默认优先级别
(2)=如何获取和设置当前线程的优先级=
getPriority():获取线程的优先级别
setPriorsity():设置线程的优先级别
说明:高优先级别的线程要抢占低优先级别线程cpu的执行权。但是只是从概率上讲。
4.=创建方式二=
(1)创建一个实现了Runnable接口的类
(2)实现类去实现Runnable中的抽象方法:run()
(3)创建实现类的对象
(4)将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
(5)通过Threead类的对象调用start():①启动线程②调用当前线程的run()–>调用Runnable类型的target的run()方法
5.比较创建线程的两种方法
开发中:=优先选择:实现Runnable接口的方式==
原因:
①实现的方式没有类的单继承性的局限性
②实现的方式更合适来处理多个线程有共享数据的情况
联系:public class Thread implements Runnable
相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中
6.线程的同步
在java中,我们通过同步机制,来解决线程的安全问题
线程安全可以简单理解为一个方法或者一个实例可以在多线程环境中使用而不会出行问题
方式一:同步代码块
说明:
(1)=操作共享数据的代码。即为需要被同步的代码=
(2)=共享数据=:多个线程共同操作的变量
(3)同步监视器,俗称:锁。任何的一个类对象,都可以充当锁。
=要求多个线程必须要共用一把锁=
方式二:同步方法
同步方法仍然设计到同步监视器,只是不需要我们显式的声明
=非静态的同步方法=,同步监视器:this
=静态的同步方法=,同步监视器是:当前类本身(当前类名.class)
方式三:
=Look锁=。-----jdk5.0新增
Synchronized与Look的异同
相同:二者都可以解决线程安全问题
不同:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器
Look需要手动启动同步(Look()),同时结束同步也需要手动的实现(unlock())
优先使用顺序:Look—>同步代码块—>(进入方法体,分配了相应资源)—>同步方法(在方法体外)
同步的方式,解决了线程的安全问题。–好处
操作同步代码时,只能有一个线程参与,其他线程等待,相当于是一个单线程的过程,效率低。
8.死锁
不同的线程分别占用对象需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成看线程的死锁
出现死锁后,不会出现异常,不会出现提示,只有所有的线程都处于阻塞状态,无法继续
线程在获得一个锁L1的情况下再去申请另一个锁L2,也就是锁L1想要包含了锁L2,也就是说在获得了锁L1,并且没有释放锁L1的情况下,又去申请获得锁L2,这个是产生死锁的最根本原因。=另一个原因是默认锁申请操作是阻塞的=
9.线程通信
涉及到三个方法
=wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。=
=notify():一旦执行此方法,就会唤醒被wait()的一个线程。如果有多个线程被wait(),就唤醒优先级别高的线程==
notifyall():一旦执行此方法,就会唤醒所有被wait的线程
说明:
wait(),notify(),notifyAll(),三个方法必须使用在同步代码块或同步方法中
wait(),notify(),notifyAll(),三个方法的调用者必须是同步代码块或同步方法中的监视器
否则,会出现IIlegalMonitorStateException异常
wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中
10.sleep()和wait()的异同
(1)相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态
(2)不同点:
两个方法声明的位置不同:Thread类中声明sleep(),Object()类中声明wait()
调用的要求不同:sleep()可以在任何场景下调用。Wait()必须使用同步代码块中
关于是否释放同步监视器,如果两个方法都是用同步代码块中,slee()不会释放,wait()会释放锁
11.创建线程的方式三:实现Callable接口。-----JDK5.0新增
(1)创建一个实现Callable的实现类
(2)实现call()方法,将此线程需要执行的操作声明在call()中
(3)创建Callble接口的实现类对象
(4)将此Callable接口实现类的对象作为形参传递到FutureTask的构造器中,创建FutureTask的对象
(5)将Future的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()方法
获取Callable中的call方法的返回值
Get()返回值即为FutrueTask构造参数Callable实现类重写的call()的返回值
12.=使用线程池(开发中使用这个)==、
(1)提供指定线程数量的线程池
(2)执行指定的线程操作。需要提供实现Runnable接口或Callable接口实现类的对象
(3)关闭连接池
Java基础—线程
本文详细介绍了Java中的程序、进程、线程概念,强调了线程的并发执行与并行的区别。讲解了线程的创建与使用,包括通过继承Thread类和实现Runnable接口两种方式,并对比了两者的优缺点。还深入探讨了线程同步、死锁、线程通信的方法,如wait()、notify()、notifyAll()。最后提到了Callable接口和线程池的使用,以及线程安全与效率的问题。
摘要由CSDN通过智能技术生成