多线程 网络编程 文件上传案例多线程

Day13 多线程

3).多线程的好处:

提高程序的运行效率,提高用户的体验度。 线程不会因为等待某个资源而进入等待状态

 

 

 

 

创建新的线程:

 *    定义类继承Thread

 *    重写方法run

 *    创建Thread子类的对象

 *    调用子类对象的方法 start()

 *    

 *  为什么继承Thread

 *    Thread类是线程对象类

 *    继承了Thread,子类也是线程对象

 *  

 *  为什么重写run

 *    Sun工程师,不清楚其他人员用线程做什么

 *    全部写在run

 *  

 *  为什么调用start

 *    线程: JVM利用Windows中的功能实现

 *    start() 调用 本地方法,开启的线程

 

 

 2.Thread类的方法,可以获取到线程名字

 *    String getName()

 *    

 *  Thread类方法 setName(String name)

 *  设置线程名字

 *  

 *  获取主线程名

 *    Thread,定义静态方法

 *    static Thread currentThread() 返回当前线程

 *    什么是当前线程: 现在运行的线程

 

 

第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用。实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。

第一种方式继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既是线程对象,有又有线程任务。

实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。

 

3.创建线程程序第二个方式,接口方式

 *  java.lang.Runnable

 *    定义类实现接口Runnable

 *    重写抽象方法run

 *    创建Thread类对象,Thread(Runnable r)

 *    调用Thread对象start()方法

 

4. 售票代码,单独定义方法

 *  pay方法,所有的代码,全是线程操作的共享数据

 *  同步整个方法,方法的定义修饰符,加同步

 *  

 *  同步方法有锁吗,同步方法的锁就是this对象

 *  

 *  静态同步方法有锁吗

 *    静态方法的对象锁可不是this

 *    锁是 本类.class对象

 *    Ticket.class

 

 

当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算。就会导致线程安全问题的产生。

 

 

6.其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,CPU的使用率更高。

 

 

7.思考:线程对象调用 run方法和调用start方法区别?

线程对象调用run方法不开启线程,仅是对象调用方法。线程对象调用start开启线程,并让jvm调用run方法在开启的线程中执行。

 

2:请描述在什么样的情况下会出现线程安全的问题。

线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态

变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程

同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

 

6.java中提供了线程同步机制,它能够解决上述的线程安全问题,请分别写出他们的格式

3.1同步代码块: 在代码块声明上 加上synchronized

synchronized (锁对象) {

可能会产生线程安全问题的代码

}

3.2同步方法:在方法声明上加上synchronized

public synchronized void method(){

       可能会产生线程安全问题的代码

}

 

3.请描述线程的几个状态。

线程包含以下几个状态:

1. 新建状态:

   调用构造方法创建线程对象后,线程就会处于新建状态。  

2.就绪状态:

   一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()

   方法。在调用start()方法后,运行run()方法之前,线程就会处于就绪状态。

3.运行状态:

  当线程获得CPU的资源后,才会进入运行状态,调用run方法。

4.阻塞状态:

  当正在运行的线程还没有运行结束,暂时让出CPU资源,让其它处于就绪

  状态的线程获得CPU资源。

5.死亡状态:

  当线程的run方法运行结束后,线程就结束了,此时线程就会死亡状态。

 

  1. 7.多线程并发和多线程并行是什么呢?

答:两个或者多个任务发送请求时,CPU只能执行一个,就会安排这些任务交替执行,由于CPU做着高速的切换,间隔的时间比较短,我们看起来像同时执行的,这就是多线程并发。

并行是两个或多个任务同时执行,前提是多核CPU

  1. 8.同步代码块和同步方法的锁是谁?

;同步代码块的锁可以是任意类型的对象;非静态同步方法的锁是this;静态方法的锁是该类的字节码文件。

  1. 3.sleep和wait的区别?

答:(1sleep是让线程睡眠,必须给相应的睡眠时间,不需要唤醒,时间到了会自动醒来,休眠时不放弃Cpu的执行权。(悲观锁机制)

2wait的是让线程等待,可以传参也可以不传参,传参是在指定的时间后等待,需要被唤醒。等待的时候放弃cpu的执行权。(乐观锁机制)

  1. 什么情况下需要同步?

:当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步.

如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码.

 

  1. 开启线程:开一个新的方法栈区
  2. 运行是方法run(
  3. 只要开启一个线程:
  4. 出现一个新的方法栈,运行

当调用一个线程对象start()方法后,此线程对象中的run()方法会被立即执行.(错误的)

Start()方法之后进入到”就绪状态”,等待操作系统分配cpu时间(正确的)

当一个线程对象的sleep()时间到了,会立即恢复运行(错误的)

sleep()醒来后,会进入到”就绪状态”,等待操作系统分配cpu时间(正确的)

Day14 网络编程

 

InetAdderss类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法,下表中列出了InetAddress类的一些常用方法。

 

 

 TCP协议分哪几个层

链路层:链路层用于定义物理传输通道通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。

网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。

运输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。

应用层:主要负责应用程序的协议,例如HTTP协议FTP协议等。

C/S 软件和服务器容易出现更新问题 , 一个更新全部需要更新,

 

B/S 网页和服务器 维护方便,客户端一个浏览器可以打开多个功能 弊端 所有浏览器内容存到浏览器  

ip地址  它是由4个字节大小的二进制数来表示

 

 HTTPFTPUDPTCP

 我们涉及到的:

 1.UDP协议:

1.数据要打包发送;

2.数据大小有限制:64K

3.不论是否有接收端,都可以发送。也称为:无状态的,不安全的协议。

  应用:视频广播,共享屏幕

 2.TCP协议:

1.数据不需要打包,使用""的方式发送和接收;

2.数据大小无限制;

3.发送时,必须要有接收端;

 

1.InetAddress类表示一个IP地址;

2.InetAddress类没有构造方法,通过静态方法获取InetAddress对象;

3.常用方法:

静态方法:public static InetAddress getByName(String 计算机名/IP地址) :

普通方法:public String getHostAddress():获取本机IP

 

2.区别在于,UDP中只有发送端和接收端,不区分客户端与服务器端,计算机之间可以任意地发送数据

TCP通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信,服务器端不可以主动连接客户端,并且服务器端程序需要事先启动,等待客户端的连接。

JDK中提供了两个类用于实现TCP程序,一个是ServerSocket类,用于表示服务器端,一个是Socket类,用于表示客户端

通信时,首先创建代表服务器端的ServerSocket对象,该对象相当于开启一个服务,并等待客户端的连接,然后创建代表客户端的Socket对象向服务器端发出连接请求,服务器端响应请求,两者建立连接开始通信。

 

 

 

public class TCPServer {

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

//1,创建服务器,等待客户端连接

ServerSocket serverSocket = new ServerSocket(8888);

Socket clientSocket = serverSocket.accept();

//显示哪个客户端Socket连接上了服务器

InetAddress ipObject = clientSocket.getInetAddress();//得到IP地址对象

String ip = ipObject.getHostAddress(); //得到IP地址字符串

System.out.println("小样,抓到你了,连接我!!" + "IP:" + ip);

 

//7,获取Socket的输入流

InputStream in = clientSocket.getInputStream();

//8,创建目的地的字节输出流   D:\\upload\\192.168.74.58(1).jpg

BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream("D:\\upload\\192.168.74.58(1).jpg"));

//9,Socket输入流中的数据,写入目的地的字节输出流中

byte[] buffer = new byte[1024];

int len = -1;

while((len = in.read(buffer)) != -1){

//写入目的地的字节输出流中

fileOut.write(buffer, 0, len);

}

 

//-----------------反馈信息---------------------

//10,获取Socket的输出流, 作用:写反馈信息给客户端

OutputStream out = clientSocket.getOutputStream();

//11,写反馈信息给客户端

out.write("图片上传成功".getBytes());

 

out.close();

fileOut.close();

in.close();

clientSocket.close();

//serverSocket.close();

}

}

 

public class TCPClient {

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

//2,创建客户端Socket,连接服务器

Socket socket = new Socket("192.168.74.58", 8888);

//3,获取Socket流中的输出流,功能:用来把数据写到服务器

OutputStream out = socket.getOutputStream();

//4,创建字节输入流,功能:用来读取数据源(图片)的字节

BufferedInputStream fileIn = new BufferedInputStream(new FileInputStream("D:\\NoDir\\test.jpg"));

//5,把图片数据写到Socket的输出流中(把数据传给服务器)

byte[] buffer = new byte[1024];

int len = -1;

while ((len = fileIn.read(buffer)) != -1){

//把数据写到Socket的输出流中

out.write(buffer, 0, len);

}

//6,客户端发送数据完毕,结束Socket输出流的写入操作,告知服务器端  (socket流不能判断读到-1 结束读操作 )

socket.shutdownOutput();

 

//-----------------反馈信息---------------------

//12,获取Socket的输入流  作用: 读反馈信息

InputStream in = socket.getInputStream();

//13,读反馈信息

byte[] info = new byte[1024];

//把反馈信息存储到info数组中,并记录字节个数

int length = in.read(info);

//显示反馈结果

System.out.println( new String(info, 0, length) );

 

//关闭流

in.close();

fileIn.close();

out.close();

socket.close();

}

1.1 文件上传案例多线程版本

 

 

 

 

实现服务器端可以同时接收多个客户端上传的文件。

l 我们要修改服务器端代码

/*

 * 文件上传多线程版本, 服务器端

 */

public class TCPServer {

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

//1,创建服务器,等待客户端连接

ServerSocket serverSocket = new ServerSocket(6666);

 

//实现多个客户端连接服务器的操作

while(true){

final Socket clientSocket = serverSocket.accept();

//启动线程,完成与当前客户端的数据交互过程

new Thread(){

public void run() {

try{

//显示哪个客户端Socket连接上了服务器

InetAddress ipObject = clientSocket.getInetAddress();//得到IP地址对象

String ip = ipObject.getHostAddress(); //得到IP地址字符串

System.out.println("小样,抓到你了,连接我!!" + "IP:" + ip);

 

//7,获取Socket的输入流

InputStream in = clientSocket.getInputStream();

//8,创建目的地的字节输出流   D:\\upload\\192.168.74.58(1).jpg

BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream("D:\\upload\\"+ip+"("+System.currentTimeMillis()+").jpg"));

//9,Socket输入流中的数据,写入目的地的字节输出流中

byte[] buffer = new byte[1024];

int len = -1;

while((len = in.read(buffer)) != -1){

//写入目的地的字节输出流中

fileOut.write(buffer, 0, len);

}

 

//-----------------反馈信息---------------------

//10,获取Socket的输出流, 作用:写反馈信息给客户端

OutputStream out = clientSocket.getOutputStream();

//11,写反馈信息给客户端

out.write("图片上传成功".getBytes());

 

客户端发送数据完毕,结束Socket输出流的写入操作,告知服务器端

out.close();

fileOut.close();

in.close();

clientSocket.close();

} catch(IOException e){

e.printStackTrace();

}

};

}.start();

}

 

//serverSocket.close();

 

posted @ 2018-04-25 15:30  阿善9  阅读(3165)  评论(0编辑  收藏  举报