您的位置:首页 > 理论基础 > 计算机网络

core java 10~12(多线程 & I/O & Network网络编程)

2014-12-06 11:51 459 查看
MODULE 10 Threads 多线程

--------------------------------

进程: 计算机在运行过程中的任务单元,CPU在一个时间点上只能执行一个进程,但在一个时间段上采用时间分片原则。

特点:

每个进程执行时需要独立的数据空间,独立分配内存,多个进程间的资源互不共享。因此进程是非常耗费资源的

线程:是程序运行时的最小执行单位

特点:

1)线程依赖于进程

2)一个进程可以分为多个线程 例:QQ

3)*多线程可以共享资源

多进程和多线程的设计目的都是为了在同时执行多个任务

多线程带来的问题:

多线程间的并发(互斥)与同步,(由共享资源引发的问题)

线程类Thread

创建自己的线程

1.继承Thread类

class MyThread extends Thread{

public void run(){

//线程处理代码

}

}

运用:

MyThread th1=new MyThread();

th1.run();//错误

th1.start();//启动该线程,执行的是run()方法中的代码

2.实现Runnable接口

class MyThread implements Runnable{

public void run(){

//线程处理代码

}

}

运用:

MyThread th1=new MyThread();

th1.start();//错误

Thread thread=new Thread(th1);

thread.start();//启动线程,执行的是th1中的run()方法

练习:

龟兔猫狗百米赛跑,要求:只要有一个先跑到终点,比赛结束

分析:设置一个多个线程都共享的数据

static boolean isRunning=true;

线程生命周期的状态:

1.Runnable就绪状态

new -->start() --> Runnable

等待JVM调度执行

2.Running状态

JVM采取时间分片策略,被调度的线程从Runnable进入Running状态

执行run()方法中的代码,一旦时间片结束,无论run()方法是否执行完,JVM都会收回该线程的执行权,调度其他处于Runnable状态的线程

Runnable <-----> Running

3.Dead死亡状态

run()方法执行结束

4.Blocked阻塞状态

1)sleep() ---> blocked

等到睡眠时间结束,该线程从bloced ---> Runnable,等待JVM重新调度

2)join() ---> blocked

调用另一线程的join()方法,使本线程进入阻塞状态,直到另一线程执行结束,本线程 blocked ---> Runnable

多线程的并发访问

----------------------------------

多个线程共享数据引发并发问题

练习:



如何解决并发访问?

synchronized关键字

1)寻找公有的对象,并在公有对象身上加锁,确保一次只能有一个线程操作该对象

synchronized(Object){

//只允许一个线程执行这部分代码

}

2)精确控制加锁的范围(或者说加锁的临界值),否则影响程序效率



线程如何从locked回到Runnable状态

------------------------------------

1)sleep 睡眠时间结束,回到Runnable

2)join() 等到另一线程执行结束,本线程回到Runnable

3)如何人为使线程从blocked ------> Runnable

a) interrupt()

人为使线程从blocked ------> Runnable

阻塞的线程一旦被调用interrupt()方法唤醒,会抛出InterruptedException,线程自己可以通过捕获该异常知道自己被中断

b)isInterrupted() 返回boolean类型,判断线程是否被中断

c)interrupted() 清除中断信息,因为一个线程被中断后会设置标志信息,isInterruped()判断为true,一旦调用interrupted()清除中断信息后,isInterruped()判断改为false

练习:ThreadState.java , 在主线程中监控另一个线程让该线程sleep后,调用interrupt()方法使其从blocked回到Runnable



线程同步问题

-------------------------------------

并发:是多个线程地位均等,共同竞争对公有对象的访问权,一次只能一个线程访问

同步:解决的是多个线程对公有对象访问的先后顺序问题

解决同步问题的思路:

1)找出公有对象,多个线程都通过公有对象进行通信

2)找出哪个线程该wait,哪个线程负责notify发通知

3)确保wait在notify之前

添加标志变量hasWait,等待的线程在调用wait()之前设置该变量,负责发通知的线程在notify()之前先判断该变量,确保notify时公有对象身上已经有wait的线程

练习:

定义一个线程CalculateThread,计算1~100的和,把结果放到一个对象中

定义一个线程PrintThread,从该对象中取出结果并打印输出

定义一个测试程序Test.java

分析:

1)属于同步问题

2)公有对象Result{int value;}

3)CalculateThread负责notify,PrintThread负责wait

注意点:

1.wait()和notify()要加synchronized

多个线程竞争公有对象res的访问锁,等待的线程间要互斥

2.等待的线程在wait之前要先设置标志变量,否则wait之后阻塞,无法设置

3.发通知的线程在notify之前要循环判定公有对象身上是否有等待的线程,有wait线程才发通知唤醒

4.while循环一定要放synchronized外面,否则拿着锁再sleep,其他线程永远拿不到res对象的访问权



setPriority() 设置线程的优先级 1~10级 优先级并不能决定线程的先后执行顺序,最终仍由JVM决定

Thread.yield() 将执行权让给优先级比自己高的线程

弃而不用的方法:

stop() / resume() / suspend()

这些方法被调用时,线程所占据的资源的锁不会被释放

死锁问题

------------------------------

若干线程去竞争有限的资源,要求同时拿到多个公有资源时,因公有资源数量有限,不能满足所有线程的需求,每个线程都只拿到部分资源且不释放,就造成死锁问题

哲学家就餐问题

如何解决?

让多个竞争资源的线程以相同的顺序去拿



MODULE 11 I/O 输入/输出

------------------------------------

java中采取流的概念, 在应用程序和外围设备之间建立一个流对象,确保无论外围设备是什么,应用程序只单一的通过访问流对象来读写数据

按流的方向,分为:

输入流InputStream

程序从输入流【读取】数据,但不能写入

read()...

输出流OutputStream

程序往输出流中【写入】数据,但不能读取

write()...

按照流的传输单位

字节流

以字节为基本传输单位,一个个字节传输

注意点:

1)流中的数据没有结构,例int数据4个字节,拆成4次传输

2)最终传输给外围设备的一定是字节流

通常以Stream结尾的都是字节流*

字符流

字节的可读性很差,字符流提供以文本的形式读写数据

通常带有Reader/Writer的都是字符流*

具有缓存功能的流

在流对象中设置缓存区,数据先放入缓存区,再一次性读写外围设备

目的:提高数据的传输性能

过滤器

对流中提供的数据进行进一步处理

字节流传输无结构,过滤器可以将字节流中的字节拼成应用程序需要的数据类型,如int double float...

*不能单独使用,一定要结合某个字节流

InputStream常见的方法

read() 每次返回一个字节,返回结果>=0为有效数据, -1表示流中数据读完

read(byte[]) 可以一次读取多个字节,放入byte[]数组中,返回一次读取成功的字节数

注意:

I/O流要与外围设备进行交互,所有资源都要手工回收

finally{

//添加资源回收代码

}

close() 关闭流对象,释放内存资源

available() 判断流是否可用

flush() 程序强制将缓存区中的数据刷新到外围设备中

字节流的层级结构

-------------------------

通常InputStream/OutputStream 前面的代表了数据源或数据目的地类型

FileInputStream 把文件作为数据源,从文件中读数据

FileOutputStream 把文件作为数据目的地,往文件中写入数据

PipedInputStream 把管道作为数据源

PipedOutputStream 把管道作为数据目的地

过滤器 对字节流进一步包装

1)BufferedInputStream

具有缓存功能的流

2)PushbackInputStream

把从流中读取的数据退回去

3)DataInputStream

能够将字节流中的字节拼成程序需要的基本数据类型

readInt(0 readDouble()...

包: java.io;

异常: IOException



练习:创建类Copy.java实现文件的拷贝

将一个文件的内容拷贝到另一文件

分析:从源文件读入数据,FileInputStream read()

写入目标文件 FileOutputStream write()

改造:以提高性能的方式

例:以提高性能的方式从指定文件啊src.txt中读取含有基本数据类型的内容

分析:

DataInputStream dis=new DataInputStream(new BufferedInputStream(new FileInputStream("src.txt")));

练习:将一个int型整数写入文件中

1)将一个个字节传输,将int拆成4个字节

2)DataOutputStream(BufferedOutputStream(FileOutputStream))



管道流PipedInputStream/PipedOutputStream

-----------------------------------------------

PipedInputStream 从管道中读取数据

PipedOutputStream 往管道中写入数据

通过管道将输入流和输出流衔接起来

练习:

创建两个线程,通过管道流实现两个线程的数据传输

一个线程Sender负责产生100个随机数,并写入管道中

一个线程Fetcher负责从管道中读取数据,并打印输出

分析; class Sender extends Thread{

PipedOutputStream pos;

public void run(){}

}

class Fetcher extends Thread{

PipedInputStream pis;

public void run(){}

}



字符流Reader/Writer

------------------------------

字节流可读性差,字符流提供以文本形式传输数据

特别的流对象

1.BufferedrReader/BufferedWriter

1)开辟缓存区提高传输性能

类似BufferedInputStream(BIS)/BOS

2)提供字符流和字符串之间的转换

类似DIS/DOS

BufferedReader: readLine() 字符流--->字符串

BUfferedWriter: write(String,off,len) 字符串---->字符流

2.InputStreamReader/OutputStreamWriter 桥梁类

最终与外围设备交互的是字节流

1)提供字节流和字符流之间的转换

InputStreamReader:字节流-----> 字符流

OutputstreamWriter:字符流----> 字节流

2)提供java标准编码UTF8和其他编码之间的转换

3.FileReader/FileWriter 是InputStreamReader/OutputStreamWriter的子类

1)具有读写文件的功能

2)作为ISR/OSW的子类,也提供字节流和字符流之间的转换

3)将编码自动转换成操作系统对应的编码格式



练习:

将一个字符串写入文件中,再读取该文件并将内容输出到控制台

分析:

字符串 --->文件

字符串----> 字符流 BuffredWriter

字符流 字节流 OutputStreamWriter FileWriter

字节流 文件 FileOutputStream

文件-----> 控制台

System.out 标准输出

System.in 键盘

System.err 标准错误

对象序列化 ObjectInputStream/ObjectOutputStream

------------------------------------------------------------

序列化:将对象转化为字节流,通常用于保存对象 的当前状态信息

使对象持久化,以备将来对该对象进行恢复

反序列化:字节流-----> Object

ObjectInputStream: Object readObject(){} 反序列化

ObjectOutputStream: writeObject(Object) 序列化

序列化实现接口:

Serializable

class Company implements Serializable{

String name;

int tel;

transient Address add; //标注该属性信息无法序列化

}

class Address{

String city;

String street;

int no;

}

注意:

1)大对象中包含小对象,序列化时要求小对象也实现了序列化接口

2)对于不能序列化的属性,需要用transient修饰

练习:ObjectTest.java



RandomAccessFile随机访问文件

-----------------------------------

以随机访问的方式读写文件中任意一段内容

skip(long) 虽是跳步,但也是从头开始跳过若干字节再进行读写

功能:

1)实现了DataInput / DataOutput接口,类似过滤器

2)读/写功能都具有

readInt() writeInt()......

3)具有操作文件的功能

4)可以随意跳到文件的某个位置开始读写

构造器中的参数:

mode 指定读/写的模式

"r":只读 "r":只写 "rw":读/写

seek(long) 跳过long 指定的若干字节数,开始读写



MODULE 12 Network网络编程

--------------------------------

ip地址 通过IP地址可以唯一定位到网络上的某台机器

port端口:人为制造的数字,代表一个服务器上某个应用的唯一标识

基于TCP/IP网络编程

传输控制协议,考虑的是传输的可靠性问题

基于UDP的网络编程

用户数据报文协议,考虑的是传输的效率问题

通讯双方满足的五要素:

1.通讯双方IP地址(两个)

2.通讯双方的PORT端口号(两个)

3.通讯双方要遵守同样的协议

java.net包:

Socket/SeverSocket:实现基于TCP/IP网络编程

DatagramSocket/DatagramPacket:为UDP协议服务

IP网络层

基本特点:

无连接的;数据可靠性不能保证的;

TCP 传输层

1)面向连接的

2)完全可靠的数据传输

3)点对点的

4)同一连接既可以发送也可以接收

5)面向字节流的

连接的简历经过了三次握手:

1)客户端发出连接请求

2)服务器回复确认

3)建立连接

Client:

构建Socket,连接指定的IP和port

---> 获取输入流/输出流

--> 对I/O流进行包装

---->读/写数据

-->释放资源(Socket/I/O)

Server:

构建SeverSocket,指定监听的端口号

--->接收客户端连接请求,获取Socket建立连接

----> 对I/O流进行包装

---->读/写数据

-->释放资源(sevrverSocket/Socket/I/O)



PrintWriter功能

String-->字节流

BufferedWriter 字符串-->字符流

OutputStreamWriter 字符流--->字节流

1.字符串--->字节流

兼具了BufferedWriter/OutputStreamWriter两者的功能

2.可以自动刷新

new PrintWriter(OS,true);

UDP 用户数据报文协议

-------------------------------------------

1)考虑的是数据传输的效率问题,可靠性不保证

2)不一定是一对一,而是多对多通讯,如广播

3)无连接的,不可靠的传输方式

DatagramSocket 负责数据的发送和接受 如邮递员

DatagramPacket 把数据打成报文对象,填入对方的IP地址和端口号 如信件

构造器:

DatagramPacket()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: