程序:是为完成特定任务,用某种语言编写的一组指令的集合,即指一段静态的代码,静态对象
进程:是程序的一次执行过程,或是正在运行的一个程序,是一个动态的过程,有它自身的产生,存在和消亡的过程——生命周期。进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
线程:进程可进一步细化为线程,是一个程序内部的一条执行路径,若一个进程同时并行执行多个线程,就是支持多线程的,线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc)
一个java应用程序java.exe,至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程,当然如果发生异常,会影响主线程
并行与并发:
并行:多个cpu同时执行多个任务,比如多个人同时做不同的事
并发:一个cpu同时执行多个任务,比如多个人同时做同一件事。
多线程的创建:方式一:继承于Thread类
1.创建一个继承于Thread类的子类
2.重写Thread类的run()-->将此线程执行的操作声明在run()中
3.创建Thread类的子类的对象
4.通过此对象调用start():启动当前线程,并调用当前线程的run()
问题一:不能通过直接调用run()方法启动线程
问题二:再启动一个线程,不可以还让已经启动start()的线程去执行,会报错
我们需要重新创建一个线程对象(new MyThread())
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.println(i);
}
}
}
}
public class ThreadTest{
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
System.out.println("hello");
}
}
方式二:实现Runnable接口
1.创建一个实现了Runnable接口的类
2.实现类去实现Runnable中的抽象方法:run()
3.创建实现类的对象
4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
5.通过Thread类的对象调用start()
比较创建线程两种方式:
开发中优先选择实现Runnable接口的方式
原因:1.实现的方式没有类的单继承性的局限性
2.实现的方式更适合用来处理多个线程有共享数据的情况
联系:public class Thread implements Runnable
相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中
测试Thread中的常用方法
1.start():启动当前线程,调用当前线程的run()
2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程的名字
5.setName():设置当前线程的名字
6.yield():释放当前cpu的执行权(有可能在下一刻cpu又分配到当前线程)
7.join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行后,线程a才结束阻塞状态。
8.stop():已过时,当执行此方法时,强制结束当前线程
9.sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒,在指定的millitime毫秒时间内,当前线程是阻塞状态。
10.isAlive():判断当前线程是否存活
线程的优先级:
1.MAX_PRIORITY:10 提高被线程优先执行的概率,不意味着只有高优先级线程执行完,低优先级才执行
MIN_PRIORITY:1
NORM_PRIORITY:5
2.如何获取设置当前线程优先级:
getPriority():获取优先级
setPriority():设置优先级
线程的五种状态:
新建,就绪(已经具备运行条件,还没分到cpu资源),运行,阻塞,死亡
就绪-->获取cpu执行权-->运行-->失去cpu执行权 或 yield()-->就绪
使用同步方法解决实现Runnable接口的线程安全问题:如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的
1.同步方法仍然涉及到同步监视器,只是不需要我们显示的声明
2.非静态的同步方法,同步监视器:this
静态的同步方法,同步监视器是:当前类本身
解决线程安全问题方式三:Lock锁
private ReentrantLock lock = new ReentrantLock(true)//实例化对象
lock.lock();
lock.unlock();
面试题:synchronized 与 lock的异同:
相同:二者都可以解决线程安全问题
不同:synchronized机制在执行完相应的同步代码后,自动释放同步监视器
lock需要手动的启动同步,结束同步也需要手动的实现
优先使用顺序:lock->同步代码块->同步方法
线程通信的例子:使用两个线程打印1-100,线程1,线程2交替打印
涉及到的三个方法:
wait():执行此方法,当前线程就进入阻塞状态,并释放同步监视器
notify():执行此方法,,就会唤醒被wait的一个线程,如果有多个线程被wait,就唤醒优先级高的
notifyAll():执行此方法,会唤醒所有被wait的线程。
说明:1.三个方法必须使用在同步代码块或同步方法中
2.三个方法的调用者必须是同步代码块或同步方法中的同步监视器,否则会出现异常。
3.三个方法是定义在java.lang.Object类中
面试题:sleep()和wait()的异同?
1.相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态
2.不同点:声明位置不同:Thread类中声明sleep(),Object类中声明wait()
调用要求不同:sleep()可以在任何需求的场景下调用。wait()必须使用在同步代码块中
如果两个方法都使用在同步代码块中sleep()不释放同步监视器,wait()释放
创建线程方式三:实现Callable接口
Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大
1.call()可以有返回值
2.call()可以抛出异常,被外面的操作捕获,获取异常信息
3.Callable支持泛型。
创建线程方式四:使用线程池,开发中常用
思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完返回池中,可以避免频繁创建销毁,实现重复利用,
好处:提高响应速度,降低资源消耗,便于线程管理
1.提供指定线程数量的线程池
ExecutorService service = Executor.newFixedThreadPool(nThreads:10);
2.执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
service.execute(new NumberThread());//适用于Runnable
service.submit(Callable callable);//适用于Callable
3.关闭连接池
service.shutdown();
java io 用于处理设备之间的数据传输,以流(stream)的方式进行
FileReader读入数据:
将文件内容读入程序中:
1.实例化File类对象,指明要操作的文件
File file = new File("hello.txt");
2.提供具体的流
FileReader fr = new FileReader(file);
3.数据的读入//read()返回读入的一个字符,如果达到文件末尾,返回-1
int data = fr.read();
while(data!=-1){
sout((char)data);
data = fr.read();}
使用read()的重载方法,read(char[] cbuf):返回每次读入cbuf数组中的字符的个数,如果达到文件末尾返回-1
char[] cbuf = new char[5];
int len;
while((len = fr.read(cbuf))!=-1){
for(int i =0;i<len;i++){
sout(cbuf[j]);}}
//错误的写法:for(int i = 0;i<cbuf.length;i++) char读入数据时是覆盖操作
4.流的关闭操作
fr.close();
FileWriter从内存中写出数据到硬盘的文件中:
说明:1.输出操作对应文件可以不存在,在输出过程中会自动创建该文件
2.如果存在:如果流使用构造器是FileWriter(file,false)/FileWriter(file):对原有文件的覆盖;FileWriter(file,true):在原有文件后接着写出
File file = new File("hello1.txt");
FileWriter fw = new FileWriter(file);
fw.write("\n");
fw.close();
使用filereader和filewriter实现文本文件复制
File srcFile = new File();
File destFile = new File();
fr.FileReader();
fw.FileWriter();
char[] cbuf = new char[5];
int len;
while((len = fr.read(cbuf))!=-1){
fw.write(cbuf,0,len);}//每次写出Len个字符
fw.close();fr.close();
结论:
1.对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
2.对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...),使用字节流处理
处理流之一:缓冲流的使用
1.BufferedInputStream,bufferedoutputstream,bufferedreader,bufferedwriter
2.作用:提供流的读取,写入的速度 提高读写速度原因:内部提供了一个缓冲区
实现非文本文件的复制:
1.造文件
File srcFile = new File();
File destFile = new File();
2.1造节点流
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
2.2造缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
3.复制的细节:读取,写入
byte[] buffer = new byte[10];
int len;
while((len = bis.read(buffer))!=-1){
bos.write(buffer,0,len)}
4.资源关闭:关闭外层流的同时,内层流也会自动关闭,关于内层流关闭,我们可以省略
bis.close();
bos.close();
处理流之二:转换流的使用:
1.转换流:属于字符流
InputStreamReader:将一个字节输入流转换为字符输入流
OutputStreamWriter:将一个字符输出流转换为字节输出流
2.作用:提供字节流与字符流之间的转换
3.解码:字节,字节数组->字符数组,字符串
编码:字符数组,字符串->字节,字节数组
4.字符集
将字节流转字符流:
FileInputStream fis = new FileInputStream();
InputStreamReader isr = new InputStreamReader(fis,"utf-8")//具体使用哪个字符集,取决于文件使用哪个字符集
System.in:标准的输入流,默认从键盘输入
System.on:标准的输出流,默认从控制台输出//都为字节流
InputStreamReader isr = new InputStreamReader(System.in);
br = new BufferedReader(isr);
网络编程的目的:直接或间接的通过网络协议与其他计算机实现数据交换,进行通讯
网络编程中两个主要问题:1.如何准确定位主机2.如何进行可靠高效的数据传输
网络编程中两个要素:1.对应问题1 ip号和端口号 2.对应问题2 提供网络通信协议:TCP/IP参考模型
通信要素一:IP和端口号
1.IP:唯一的标识Internet上的计算机
2.在java中使用InetAddress类代表IP
3.IP分类:IPv4和IPv6;万维网和局域网
4.域名:
5.本地回路地址:127.0.0.1 对应着localhost
6.如何实例化InetAddress:两个方法:getByName(String host),getLocalHost();
两个常用方法:getHostName()/getHostAddress()
7.端口号标识正在计算机上运行的进程,不同的进程有不同的端口号,范围:0~65535
8.端口号与IP地址的组合得出一个网络套接字:Socket
TCP协议网络编程:例子1:客户端发送信息给服务端,服务端将数据显示在控制台上
客户端:
1.创建socket对象,指明服务器端的ip和端口号
InetAddress inet = InetAddress.getByName("192.168.14.100")
Socket socket = new Socket(inet,8899)
2.获取一个输出流,用于输出数据
OutputStream os = socket.getOutputStream();
3.写出数据的操作
os.wrute("nihao".getBytes());
4.资源的关闭
os.close();
socket.close();
服务端:
1.创建服务器端的ServerSocket,指明自己端口号
ServerSocket ss = new ServerSocket(8899);
2.调用accept()表示接收来自于客户端的socket
Socket socket = ss.accept();
3.获取输入流
InputStream is = socket.getInputStream();
4.读取输入流中的数据
ByteArrayOutputStream baos = new ByteArrayOutputStream();
5.资源关闭