HeadFirstJava——13_网络与线程
来源:互联网 发布:bit.edu.cn域名代表 编辑:程序博客网 时间:2024/05/24 00:59
网络
客户端与服务器的应用程序通过socket连接进行通信;
socket代表两个应用程序之间的连接,它们
一、客户端程序
1 客户端工作方式
1.1 连接——如何建立客户端与服务器之间的初始连接?
用户通过建立socket连接来连接服务器;
1.2 传送——如何传达信息到服务器?
用户送出信息给服务器;
1.3 接收——如何接受来自服务器的信息?
用户从服务器接受信息;
2 建立socket连接
创建socket连接必须知道服务器的两个信息——IP地址和端口号;
socket连接的建立代表两台机器之间存有对方的信息,包括网络地址和TCP的端口号;
Socket socket = new Soccket("<IP地址>", <端口号>);
如下,客户端发起socket连接,对应服务器接收socket连接并存储客户端的IP地址和端口号;
Socket socket = new Socket("196.164.1.103", 5000);
注意:
TCP端口只是一个16位宽、用以识别服务器上特定程序的数字;
一个地址可以有65535个不同的端口号可用,其中0~1023的TCP端口号是保留给已知的特定服务使用,1024~65535之间可任意挑选;
网页服务器HTTP端口号——80;HTTPS端口号——443;
POP3邮件服务器端口号——110;SMTP邮局交换服务器端口号——25;
FTP服务器端口号——20;Telnet服务器端口号——23;
Time服务器端口号——37;
如果没有端口号,服务器就无法分辨客户端连接哪个应用程序的服务;
3 从socket上读取数据——使用BufferedReader
Client <-- BufferedReader(缓冲区的字符) <-- InputStreamReader(转换成字符) <-- socket输入流(来自服务器的字节) <-- Server
a 建立对服务器的Socket连接
Socket socket = new Socket("127.0.0.1", 5000);
b 建立连接到Socket上底层输入串流的InputStreamReader
InputStreamReader是个底层与高层串流的桥梁,socket.getInputStream()从socket取得输入串流;
InputStreamReader stream = new InputStreamReader(socket.getInputStream());
c 建立BufferedReader来读取
将BufferedReader链接到InputStreamReader;
BufferedReader reader = new BufferedReader(stream);String message = reader.readLine();
4 写数据到socket上——使用PrintWriter
Client --> PrintWriter --> socket输出流 --> Server
a 对服务器建立socket连接
Socket socket = new Socket("127.0.0.1", 5000);
b 建立链接到Socket的PrintWriter
PkrintWriter是字符数据和字节之间的转换桥梁,可衔接String和Socket两端;
PrintWriter writer = new PrintWriter(socket.getOutputStream());
c 写入数据
println()会在送出的数据后面加上换行;
print()不会加上换行;
writer.println("Message to send.");writer.print("Another message.");
二、服务器程序
1 服务器工作方式
1.1 服务器应用程序对特定端口创建出ServerSocket
服务器应用程序监听4242端口的客户端请求;
ServerSocket serversocket = new ServerSocket(4242);
1.2 客户端对服务器应用程序建立socket连接
客户端事先知道服务器应用程序的IP地址和端口号;
Socket socket = new Socket("190.165.1.103", 4242);
1.3 服务器创建与客户端通信的新socket
accept()方法会在等待用户的socket连接时闲置着;当用户连接上,此方法会返回一个Socket(在不同的端口号),以便于客户端通信;
Socket和ServerSocket的端口不通,因此ServerSocket可空出来等待其他用户;
Socket socket = serversocket.accept();
线程
一、线程与Thread概念
1 线程
线程是独立的线程,代表独立的执行空间;
每个Java应用程序会启动一个主线程——将main()方法放在自己执行空间的最开始处;
2 Thread
Thread是Java中表示线程的类,有启动、连接、闲置线程的方法;
要建立线程就得创建Thread,Thread对象代表线程;当需要新的线程时建立Thread对象;
3 执行空间
当有超过一个以上的执行空间,看起来像是好几件事情同时发生;
实际上只有真正的多处理器系统能同时执行好几件事情;
但使用Java的线程让其看似同时在执行中,即执行动作可在执行空间飞快地来回交换;
二、启动线程
a 建立Runnable对象(线程的任务)
编写实现Runnable的类,即对线程要执行的任务的定义;
Runnable threadJob = new MyRunnable();
b 建立Thread对象(执行工人)并赋值Runnable(任务)
把Runnable对象传给Thread的构造函数,告诉Thread对象把哪个方法放在执行空间去运行;
Thread myThread = new Thread(threadJob);
c 启动Thread
新的线程启动后,把Runnable对象的方法放到新的执行空间中;
myThread.start();
注意:每个Thread需要一个任务来执行。
三、Runnable接口
1 Runnable接口只有一个方法——public void run();
run()方法是新线程所执行的第一项方法;
2 实现Runnable接口
public class MyRunnable implements Runnable{// 将要运行的程序放在这里public void run(){go();}public void go(){doMore();}public void doMore(){System.out.println("top o' the stack");}}calss ThreadTeater{public static void main(String[] args){Runnable threadJob = new MyRunnable();Thread myThread = new Thread(threadJob);// 调用start()让线程开始执行// 在此之前,只是个Thread实例,不是真正的线程myThread.start();System.out.println("back in main");}}
四、线程状态
新建
Thread实例已创建,但还未启动;
Thread t = new Thread(r);
1 可执行
启动线程时,变成可执行状态,表示准备好要执行,只要轮到它就开始;
建立新的执行空间,处于可执行状态等待被跳出来执行;
t.start();
2 执行中
哪个线程执行由Java虚拟机的线程调度机制决定;
3 暂时不可执行(被堵塞状态)
调度器有时会将线程移出可执行状态,或线程本身的程序会sleep(),或线程调用某个被锁住的对象上的方法(等待锁住该对象的线程释放该对象才能继续);
五、线程调度器
线程调度器决定哪个线程从等待状况中被调出来运行,以及何时把哪个线程送回等待被执行的状态;
程序员没有API来控制调度器;
六、使用Thread.sleep()
调用Thread.sleep()方法强迫某线程离开执行中的状态;
该方法可能会抛出InterruptedException异常,因此对其调用必须包在try/catch块中或声明出来;
七、同步化
1 线程缺点
两个及以上的线程存取单一对象的数据,即两个不同执行空间上的方法都在堆上对同一个对象执行getter或setter;
可能会产生并发性问题,导致数据损毁;
public static void main(String[] args){// 将任务初始化RyanAndMonicaJob theJob = new RyanAndMonicaJob();// 创建出使用相同任务的两个线程,代表两个线程都会存取同一个账户Thread one = new Thread(theJob);Thread two = new Thread(theJob);one.setName("Ryan");two.setName("Monica");one.start();two.start();}
2 解决办法——同步化
要保护数据,就使用synchronized关键字修饰方法使其每次只能被单一的线程存取;
synchronized代表线程需要一把钥匙来存取被同步化的线程;
同步化的意义在于指定某段工作要在不能分割的状态下执行;
对象的锁只会在同步化的方法上其作用;
锁不是配在方法上,而是在对象上;
每个Java对象都有一个锁,每个锁只有一把钥匙;
有时,不需要对整个方法同步化,可对部分语句块进行同步化;
public void go(){doStuff();synchronized(this){criticalStuff();moreCriticalStuff();}}
3 同步化缺点——死锁
死锁发生是因为两个线程互相持有对象正在等待的东西,没有方法可以脱离这个情况,因此两个线程一直等下去;
Java没有处理死锁的机制;
- HeadFirstJava——13_网络与线程
- HeadFirstJava——2_类与对象
- HeadFirstJava——7_继承与多态
- HeadFirstJava——8_接口与抽象类
- HeadFirstJava——10_数字与静态
- HeadFirstJava——1_基本概念
- HeadFirstJava——3_变量
- HeadFirstJava——5_编写程序
- HeadFirstJava——11_异常处理
- HeadFirstJava——14_数据结构
- HeadFirstJava学习心得——网络编程
- HeadFirstJava——9_构造器与垃圾收集器
- HeadFirstJava——4_对象的行为
- HeadFirstJava——12_序列化和文件的输入/输出
- HeadFirstJava学习心得——javaGUI编程
- HeadFirstJava——6_Java API
- HeadFirstJava——十大遗珠之憾
- HeadFirstJava 10数字与静态
- splay树的一些基本操作 c语言代码
- Poj 1274 The Perfect Stall【二分匹配】
- There is a problem with the configuration server.(usr/lib/libgconf2-4/gconf-sanity-check-2 ...)
- maven 源
- 二维数组
- HeadFirstJava——13_网络与线程
- 共轭分布
- ExtJS 4.1 TabPanel动态加载页面并执行脚本
- android实现底部菜单栏
- 学习之maven(3)
- Spring aop 注解方式怎么获得执行了目标的某个方法?
- 网站建设-PHPWAMP 学习笔记
- 人月神话读书笔记(15)----另外一面
- 开源项目Baby学习