线程与进程使用详解

1.多线程

并发:指两个或多个事件在同一个时间段里发生
并行:指两个或多个事件在同一个时刻(同时发生)里发生
进程:是指一个内存中运行的内存程序,每个进程都有独立的内存空间,一个应用程序可以同时运行多个进程,进程也是程序的一次执行过程,是系统运行程序的基本单位,系统运行程序既是一个进程从创建,运行到消亡的过程。
简单来说,点击一个程序执行,进入到内存,占用一些内存来执行,这个进入内存的程序叫进程。
线程:是进程的执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程,一个进程中也可以有多个线程,这个应用程序也可以称之为多线程程序。
简而言之,一个程序的执行必须有一个进程,一个进程可以有多个线程
线程属于进程,是进程中的一个执行单元,负责程序的执行
线程调度

  • 分时调度:
    所有线程轮流使用cpu的使用权,平均分配每个线程占用cpu的时间
  • 抢占式调度:
    优先让优先级高的线程使用cpu,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的就是抢占式调度
    主线程:执行主(main)方法的线程
    单线程程序:Java当中只有一个线程,执行从main方法开始,从上到下依次执行
    创建多线程的第一种方法:创建Thread类的子类
    实现步骤
    1.创建一个Thread类的子类
    2.在Thread类的子类中重写Thread类的Run方法,设置线程任务(该线程要做什么?)
    3.创建Thread类的子类对象
    4.调用Thread类中的start方法,开启新的线程,执行Run方法
    void start() 使该线程开始执行,虚拟机调用线程的Run方法
    结果是两个线程并发的运行,当前线程(main线程)与另一个线程(新创建的线程),执行其中的Run方法
    多次执行一个线程是非法的,特别是当线程已经结束执行后,不能再重新执行
    获取线程的名称
    1.使用Thread类中的方法getName()
    String getName() 返回该线程的名称
    2.可以先获取到当前正在执行的线程,使用线程中的方法getName()获取线程的名称
    static Thread currentThread() 返回当前正在执行的线程对象的引用
    设置线程名称(了解)
    1.使用Thread类中的setName()方法
    String setName(String Name) 改变线程的名字,使之和传入的参数名称保持一致
    2.创建一个带参数的构造方法,参数传递线程的名称,调用父类的带参构造方法把线程名称传递给父类,让父类(Thread)给子线程起一个名字 Thread(String name) 分配新的Thread对象
    常用方法
    public static void sleep(Long millis);使当前正在运行的线程以指定的毫秒数暂停(暂时停止执行),毫秒数结束之后,线程继续执行
    创建多线程程序的第二种方式:实现Runnable接口
    Runnable接口应该由那些打算通过某一线程执行其实例的类来实现,类必须定义一个成为run的无参数函数
    Thread(Runnable target) 分配新的Thread对象
    Thread(Runnable target,String name) 分配新的Thread对象
    1.创建一个Runnable接口的实现类
    2.在实现类里重写Runnable接口的run方法,设置线程任务
    3.创建一个Runnable接口的实现类对象
    4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
    5.调用Thread类中的start方法,开启新的线程执行run方法
    实现Runnable接口创建多线程的好处
    1.避免了继承的局限性
    一个类只能继承一个类,类继承了Thread类就不能继承其他类
    实现Runnable接口还可以继承其他的类,实现其他的接口
    2.增加了程序的拓展性,降低了程序的耦合性(解耦)
    实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)
    实现类中重写了run方法用来设置线程任务
    创建Thread类对象,调用start方法,用来开启新的线程
    匿名内部类方法实现线程的创建
    匿名:没有名字
    内部类:写在其他类内部的类
    匿名内部类作用:简化代码
    把子类继承父类,重写父类方法,创建子类的对象合一步完成
    匿名内部类的最终产物:
    子类/实现类对象,而这个类没有名字

2.线程安全

同步代码块:解决线程安全的第一种方案
格式:
synchron(锁对象){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
注意:1.同步代码块中的锁对象可以使用任意的对象
2.但是必须保证多个线程使用的锁对象是同一个
3.锁对象的作用:
把同步代码块锁住,只让一个代码块在锁对象中执行
同步方法:解决线程安全的第二种方案
使用步骤:
1.把访问了共享数据的代码抽取出来放到一个方法中
2.在方法上添加synchronized修饰符
格式:定义方法的格式
修饰符 synchronize 返回值类型 方法名(参数名){
可能会出现线程安全问题的代码}
Lock锁:解决线程安全问题的第三种方法
Lock实现提供了比使用synchronize方法和语句可获得的更广泛的锁定操作
viod lock() 获取锁
viod unlock() 释放锁
使用步骤
1.在成员位置创建一个ReentrantLock对象
2.在可能出现线程安全问题的代码前调用Lock接口中的lock方法获取锁
3.在可能出现线程安全问题的代码前调用Lock接口中的unlock方法释放锁

3.线程状态

NEW(新建):线程刚被创建,但是尚未启动,还没调用start方法
Runnable(可运行):线程可以在Java虚拟机中运行的状态,可能正在运行自己的代码,也可能没有,这取决于操作系统处理器
Blocked(锁阻塞):当一个线程试图获取一个对象锁,而该对象锁被其他程序所持有,则该线程进入Blocked状态,当该线程持有锁时,该线程进入Runnable状态
Waiting(无限等待):一个线程在等待另一个线程进行(唤醒)动作时,该线程进入Waiting状态。进入这个状态后不能自行唤醒,必须等待另一个线程调用notify方法或者notifyAll方法才能唤醒
TimedWaiting(计时等待):通Waiting状态,有几个方法有超时参数,调用他们将进入这个状态,这个状态将一直保持到超时期满或者接收到唤醒通知,带有超时参数的常用方法有Thread.sleep(),Object.wait
Teminated(被终止):因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡
进入到TimedWaiting(计时等待)有两种方法
1.使用sleep(long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable或者Blocked状态
2.使用wait(long m)方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,线程睡醒进入到Runnable或者Blocked状态
调用wait和notify方法需要注意的细节
1.wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用得wait方法后的线程
2.wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的
3.wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这两个方法

4.线程池

Executors类:线程池的工厂类,用来生成线程池
Executors类中的静态方法
static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用固定线程数的线程池
参数
int nThreads:创建线程池中包含的线程数量
返回值
ExecutorService接口,返回的也是ExecutorService接口的实现类对象,我们可以使用ExecutorService接口接受(面向接口编程)
ExecutorService:线程池接口
用来从线程池中获取线程,调用start方法,执行线程任务
submit(Runnable task) 提交一个Runnable任务用于执行关闭/销毁线程池的方法
void shutdown()
线程池的使用步骤
1.使用线程池的的工厂类Executors里边提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池
2.创建一个类,实现Runnable接口,重写run方法,设置线程任务
3.调用ExecutorService中的方法submit,传递线程任务(实现类),开启线程,执行run方法
4.调用ExecutorService中的方法shutdown销毁线程池(不建议执行)

5.软件结构

C/S结构:全称为Client/Server结构,是指客户端和服务器结构
B/S结构:全称为Browser/Server结构,是指浏览器和服务器结构
两种架构各有优势,但无论哪种架构都离不开网络的支持,网络编程,就是在一定的协议下,实现两台计算机得通信的程序
网络通信协议:指的是连接不同操作系统和不同硬件体系结构的互联网络引提供通信支持,是一种网络通用语言
UDP :是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规范
TCP:是一种传输控制协议,一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。TCP旨在适应支持多网络应用的分层协议层次结构。 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务。TCP假设它可以从较低级别的协议获得简单的,可能不可靠的数据报服务。 原则上,TCP应该能够在从硬线连接到分组交换或电路交换网络的各种通信系统之上操作。
IP地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。是指互联网协议地址,又译为网际协议地址。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
端口号:所谓的端口,就好像是门牌号一样,客户端可以通过ip地址找到对应的服务器端,但是服务器端是有很多端口的,每个应用程序对应一个端口号,通过类似门牌号的端口号,客户端才能真正的访问到该服务器。为了对端口进行区分,将每个端口进行了编号,这就是端口号
TCP通信:面向连接的通信,客户端和服务端必须的经过三次握手,建立逻辑连接,才能通信(安全)
通信的步骤
服务器端先启动
服务器端不会主动的请求客户端
必须使用客户端请求服务器端
客户端和服务端就会建立一个逻辑连接
而这个连接中包含一个对象
这个对象就是IO对象
客户端和服务器端就可以使用IO对象进行通信
通信的数据不仅仅是字符
所以IO对象是字节流对象
客户端和服务器端进行一个数据交换需要四个IO流对象
服务器端必须明确两件事情
1.多个客户端同时和服务器进行交互,服务器必须明确和那个客户端进行的交互
在服务器端有一个方法,叫accept客户端获取到请求的客户端对象
2.多个客户端同时和服务器进行交互,就需要使用多个IO流对象
服务器是没有IO流的,服务器可以获取到请求的客户端对象Socket
使用每个客户端Socket中提供的IO流和客户端进行交互
服务器使用客户端的字节输入流读取客户端发送的数据
服务器使用客户端的字节输出流给客户端回写数据
简单记:服务器使用客户端的流跟客户端进行交互
表示客户端的类Socker:此类实现客户端套接字。套接字是两台机器间通信的端点
套接字:包含了IP地址和端口号的网络单位
构造方法:
Socker(String host,int port) 创建一个流套接字并将其连接到指定主机上的指定端口号
参数
String host:服务器主机的名称/服务器的ip地址
int port:服务器的端口号
成员方法
OutputStream getOutputStream() 返回此套接字的输出流
InputStream getInputStream() 返回此套接字的输入流
viod close() 关闭套接字
实现步骤
1.创建一个客户端对象 Socket,构造方法绑定服务器的Ip地址和端口号
2.使用 Socket对象中的方法 getoutputstream()获取网络字节输出流 Outputstream对象
3.使用网络字节输出流 Outputstream)对象中的方法 write,给服务器发送数据
4.使用 Socket对象中的方法 getinputstream()获取网络字节输入流 Inputstream对象
5.使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据
6.释放资源( Socket)
注意:1.客户端和服务器端进行交互,必须使用 Socket中提供的网各流,不能使用自己创建的流对象
2.当我们创建客户端对象 Socket的时候,就会去请求服务器和服务器经过3次握手建立连接通路
这时如果服务器没有启动,那么就会抛出异常
如果服务器已经启动,那么就可以进行交互了

你可能感兴趣的:(实验室)