首页 > 技术文章 > 多线程&socket

javaydsj 2021-08-11 10:26 原文

一、进程&线程

进程:正在执行的程序,每个进程都是由程序代码组成;
线程:代码在进程中执行的流程;

比如:打开的迅雷就是一个进程,下载的任务就是线程,所以一个进程可以有多个线程。

线程实现方式:
1、继承Thread类
在类中重写run方法,run方法里是要执行的任务,然后创建对象,通过对象调用start方法。

2、实现Runnable接口
在类中重写run方法,创建Thread对象,将接口的实现类作为参数传给Thread类,然后调用Thread类的start方法

总结:只有调用Thread类的start方法才能开启一个线程,thread的run方法只是一个普通方法。

二、Synchronized&Lock

synchronized: 代码块被synchronized修饰后,其他线程便只能一直等待,只有当该代码块执行结束或者出现异常,才会释放锁。

lock: 不让等待的线程一直无期限地等待下去,使用lock。

总结:Lock是一个接口,而synchronized是Java中的关键字;
synchronized在发生异常时,会自动释放线程占有的锁,使用Lock时需要在finally块中释放锁;
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。

三、线程池

如果程序中有大量线程任务,将会花费大量时间创建和销毁线程,系统效率很低,而线程池里的每一个线程任务结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用,因而借助线程池可以提高程序的执行效率。

线程池类型:

• FixedThreadPool:固定线程数线程池,提交任务时创建线程,直到池的最大容量,如果有线程非预期结束,会补充新线程
• CachedThreadPool:可变线程池,它犹如一个弹簧,如果没有任务需求时,它回收空闲线程,如果需求增加,则按需增加线程,不对池的大小做限制
• SingleThreadExecutor:单一线程。处理不过来的任务会进入FIFO队列等待执行
• SecheduledThreadPool:周期性线程池。支持执行周期性线程任务

fixedPool提交线程,runnable无返回值,callable有返回值,但主线程被阻塞的时候,需要等待任务线程返回才能拿到结果;
schedulerPool调用submit,提交任务时,跟普通pool效果一致;调用schedule提交任务时,则可按延迟,按间隔时长来调度线程的运行。

四、socket

1、socket服务端

 

 public class ServiceServer {
	
		public static void main(String[] args) throws Exception {
	
			// 创建一个serversocket,绑定到本机的8899端口上
			ServerSocket server = new ServerSocket();
			server.bind(new InetSocketAddress("localhost", 8899));
	
			// 接受客户端的连接请求;accept是一个阻塞方法,会一直等待,到有客户端请求连接才返回
			while (true) {
				Socket socket = server.accept();
				new Thread(new ServiceServerTask(socket)).start();
			}
		}
	
	}   

  2、socket客户端

public class ServiceClient {

	public static void main(String[] args) throws Exception {
		
		/*ServiceIterface service = ProxyUtils.getProxy(ServiceIterface.class,"methodA",hostname,port);
		Result = service.methodA(parameters);*/
		
		// 向服务器发出请求建立连接
		Socket socket = new Socket("localhost", 8899);
		// 从socket中获取输入输出流
		InputStream inputStream = socket.getInputStream();
		OutputStream outputStream = socket.getOutputStream();

		PrintWriter pw = new PrintWriter(outputStream);
		pw.println("hello");
		pw.flush();

		BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
		String result = br.readLine();
		System.out.println(result);
		
		inputStream.close();
		outputStream.close();
		socket.close();
		
		
	}
} 

  3、业务方法

public class GetDataServiceImpl {
	
	public String getData(String param){
		
		return "ok-"+param;
	}
}

  4、线程实体类

 

public class ServiceServerTask implements Runnable{
	Socket socket ;
	InputStream in=null;
	OutputStream out = null;
	
	public ServiceServerTask(Socket socket) {
		this.socket = socket;
	}

	//业务逻辑:跟客户端进行数据交互
	@Override
	public void run() {
		 try {
			//从socket连接中获取到与client之间的网络通信输入输出流 
			in = socket.getInputStream();
			out = socket.getOutputStream();
				
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			//从网络通信输入流中读取客户端发送过来的数据
			//注意:socketinputstream的读数据的方法都是阻塞的 
			String param = br.readLine();
				
			GetDataServiceImpl getDataServiceImpl = new GetDataServiceImpl();
			String result = getDataServiceImpl.getData(param);
				
			//将调用结果写到sokect的输出流中,以发送给客户端
			PrintWriter pw = new PrintWriter(out);
			pw.println(result);
			pw.flush();
						
		} catch (IOException e) {		 
			e.printStackTrace();
		}finally{
			try {
				in.close();
				out.close();
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		
	}

}

  更多java、大数据学习面试资料,请扫码关注我的公众号:

 

推荐阅读