Java多线程机制及其在socket编程中的应用

2018-03-29 00:30郑逸凡
赤峰学院学报·自然科学版 2018年9期
关键词:服务器端线程进程

郑逸凡

(福州外语外贸学院,福建 福州 350202)

1 进程与线程

在操作系统中,进程是程序的一次执行,比如当双击某个可执行文件后,系统就创建一个进程专门执行这个程序的代码,在执行过程中,进程会申请、持有或释放操作系统资源(文件、内存等).在操作系统发展早期,进程是资源分配、调度、执行的基本单位,但由于进程持有系统资源等,调度时系统开销很大,于是便出现了轻量级进程——线程.

一个进程可拥有多个线程,这些线程共享此进程所持有的系统资源.现代操作系统中,调度、执行的基本单位变成了线程,进程则还是资源分配的基本单位.由于线程本身几乎不持有系统资源,在调度时系统开销就很小.操作系统可以拥有多个进程,感觉就像多个程序同时在执行;进程可以拥有多个线程,感觉就像一个程序可以同时做多件事情.

2 Java中的多线程API

多线程编程是指让程序使用多个线程同时分别做一件事情的不同部分,或者同时做不同的事情,但并不是所有的事情都适合多线程,多线程编程的目的是提高程序执行效率、提高人们的工作效率.

2.1 继承Thread类创建线程

在Java中,Thread类是所有线程类的超类,开发人员可以编写一个类继承Thread,并重写run方法,在run方法里面编写线程将要执行的代码.创建线程对象后,只需要调用start()方法即可让线程进入就绪队列,等待操作系统调度.需要特别注意的是调度具有随机性和随时性,也就是说无法确定下一次调度哪个线程,也无法确定什么时刻进行调度.在Java中,继承Thread类创建线程的代码如下:

public class ThreadTest{

public static void main(String[]args){

MyThread myThread=new MyThread();

myThread.start();

}

}

class MyThread extends Thread{

@Override

public void run(){

System.out.println("自己创建的线程执行了");

}

}

2.2 实现Runnable接口创建线程

除了继承Thread类重写run方法外,在简单的情况下,还可通过实现Runnable接口的方式编写线程执行的代码,具体实现代码如下:

Thread thread=new Thread(new Runnable(){

@Override

public void run(){

System.out.println("Runnable接口方式实现多线程");

}

});

3 线程安全及同步控制

一个数据,如一个对象或对象中的某个字段,如果有多个线程可以同时访问它,就可能会出现线程安全问题:数据错乱、程序出错或其他无法预知的问题.比如线程1要遍历一个list集合,线程2要把这个list集合清空,如果这两个线程同时执行就可能会出现线程安全问题.线程同步控制,即使用某种方式使得一个线程在操作完某个数据前,别的线程无法操作这个数据,从而避免多个线程同时操作一个数据,进而避免线程安全问题.

3.1 synchronized同步锁机制

在Java中每个对象都有一把锁,同一时刻只能有一个线程持有这把锁,线程可以使用synchronized关键字向系统申请某个对象的锁,得到锁之后,别的线程再申请该锁时,就只能等待.持有锁的线程在这次操作完成后,可以释放锁,以便其他线程可以获得锁.例如,以synchronized代码块实现同步锁机制的主要代码如下:

Thread thread1=new Thread(new Runnable(){

@Override

public void run(){

synchronized(list){

for(int i=0;i<list.size();i++){

System.out.println(list.get(i));

}

}

}

});

Thread thread2=new Thread(new Runnable(){

@Override

public void run(){

synchronized(list){

list.clear();

}

}

});

3.2 wait/notify等待/通知机制

对于稍复杂的情况,比如多个线程需要相互合作有规律的访问共享数据,就可以使用wait/notify机制,即等待/通知机制,也称等待/唤醒机制.

等待/通知机制建立在synchronized同步锁机制的基础上,即在同步代码块(或同步方法)内,如果当前线程执行了lockObject.wait()(lockObject表示提供锁的对象),则当前线程立即暂停执行,并被放入阻塞队列,并向系统归还所持有的锁,并在lockObject上等待,直到别的线程调用lockObject.notify().如果有多个线程在同一个对象上等待,notify()方法只会随机通知一个等待的线程,也可以使用notifyAll()方法通知所有等待的线程.被通知的线程获得锁后会进入就绪队列.

3.3 信号量机制

假设线程1需要同时拥有资源A和资源B才能工作,线程2需要同时拥有资源A和资源B才能工作,在进行同步控制时有可能出现这种情况:线程1拥有资源A,线程2拥有资源B,两个线程相互等待对方先释放资源,并会一直这么僵持下去,这种情况称为死锁.

为了避免死锁,可以使用信号量机制:线程在尝试申请某个资源前都要判断能否一次性就获得所有需要的资源,如果能,就申请,如果不能,则不申请,一直等到可以一次性获得所有资源.

4 多线程机制在socket编程中的应用

网络编程,主要是指基于TCP的网络通信编程,在Java中网络编程是使用Socket类实现,因此也称为socket编程.socket编程模型中有服务器端和客户端,服务器端使用ServerSocket创建,一般有固定的IP地址和端口号,方便向外界提供服务.客户端可以有多个,并且使用Socket主动连接服务器.连接后,服务器端也创建一个Socket对象表示这次连接.

4.1 socket编程的服务器端实现

在Java中实现socket编程,服务器端要做的事情主要有:创建服务器对象ServerSocket;等待客户端的连接请求,收到请求后即返回表示这次连接的Socket对象;开启新的线程专门处理这个连接;获得连接的输入输出流,并按照一定的规则进行数据交换;关闭连接(关闭连接时会自动关闭IO流).服务器端socket编程的主要代码如下:

public class ServerTest{

public static void main(String[]args){

try{

ServerSocket server=new ServerSocket(10002);

while(true){

Socket socket=server.accept();

MyThread myThread=new MyThread(socket);

myThread.start();

}

}catch(IOException e){

e.printStackTrace();

}

}

}

4.2 socket编程的客户端实现

在Java中实现socket编程,客户端要做的事情主要有:创建Socket对象,即向服务器申请连接;获得连接的输入输出流,并按照一定的规则进行数据交换;最后关闭连接(关闭连接时会自动关闭IO流).客户端socket编程的主要代码如下:

public class ClientTest{

public static void main(String[]args)throws IOException{

Socket socket=new Socket("localhost",10001);

InputStream inputStream=socket.getInputStream();

OutputStream outputStream=socket.getOutputStream();

byte[]buff=new byte[1024];

int len=inputStream.read(buff);

System.out.println(new String(buff,0,len));

socket.close();

}

}

猜你喜欢
服务器端线程进程
基于C#线程实验探究
Linux环境下基于Socket的数据传输软件设计
基于国产化环境的线程池模型研究与实现
债券市场对外开放的进程与展望
改革开放进程中的国际收支统计
浅析异步通信层的架构在ASP.NET 程序中的应用
浅谈linux多线程协作
基于Qt的安全即时通讯软件服务器端设计
基于C/S架构的嵌入式监控组态外设扩展机制研究与应用
社会进程中的新闻学探寻