0000-0010

0001 多线程入门

第一节 进程与线程的区别
1. 什么是进程:进程是一个应用程序
2.什么是线程:线程是一条执行路径,main是主线程,自己创建的是子线程。一个进程中最少有一个线程(主线程)
3.创建线程三种方式:
1)继承Thread
2)实现Runnable接口
3使用匿名内部类方式
Thread thread =new Thread(new Runnable(){})
4.为啥不能直接调用run方法启动线程?
如果直接调用run方法其实是用主线程在跑,没有起到多线程的作用,所以要调用start方法才行
5.主线程跟子线程没有关联,所有哪个执行完并不能控制,但是开始执行的时候一定是主线程开始执行先的

6.在实现Runnable接口时,不能直接用new Runnable().start()这种方式去执行线程,应为Runnable中并没有start

   方法,所有需要new Thread(),然后将Runnable传入到Thread中,最后才调用start()方法

7. 线程5个状态:

0000-0010_第1张图片

 

0002 多线程之间实现同步

1.什么是线程安全问题?

多个线程同时共享一个全局变量或者静态变量,做写的操作

2.怎样解决线程安全问题?

1)使用synchronize  2) jdk1.5 并发lock  

synchronize使用方法(只适用于单个jvm,集群无效):

1)同步代码块:将可能发生线程安全问题的代码包裹起来,synchronize(同一个数据){  }

2)同步函数: 在方法上加synchronize

3)静态同步函数:在方法加上static 使用synchronize修饰

3.多线程死锁

class ThreadTrain6 implements Runnable {
	// 这是货票总票数,多个线程会同时共享资源
	private int trainCount = 100;
	public boolean flag = true;
	private Object mutex = new Object();

	@Override
	public void run() {
		if (flag) {
			while (true) {
				synchronized (mutex) {
					// 锁(同步代码块)在什么时候释放? 代码执行完, 自动释放锁.
					// 如果flag为true 先拿到 obj锁,在拿到this 锁、 才能执行。
					// 如果flag为false先拿到this,在拿到obj锁,才能执行。
					// 死锁解决办法:不要在同步中嵌套同步。
					sale();
				}
			}
		} else {
			while (true) {
				sale();
			}
		}
	}

	
	public synchronized void sale() {
		synchronized (mutex) {
			if (trainCount > 0) {
				try {
					Thread.sleep(40);
				} catch (Exception e) {

				}
				System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - trainCount + 1) + "张票.");
				trainCount--;
			}
		}
	}
}

public class DeadlockThread {

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

		ThreadTrain6 threadTrain = new ThreadTrain6(); // 定义 一个实例
		Thread thread1 = new Thread(threadTrain, "一号窗口");
		Thread thread2 = new Thread(threadTrain, "二号窗口");
		thread1.start();
		Thread.sleep(1);
		threadTrain.flag = false;
		thread2.start();
	}

}

  

0003多线程之间通讯wait和notify

1.多线程通讯:多个线程操作一个共享变量,但是操作的方法不同

2.wait要和notify,synchronize配合使用

3.为啥wait和notify定义在Object 中

 有的时候要用多线程进行同步,锁有时候是自定义的,自定义有可能是类,所以直接把方法定义到父类Object中,这样所有的类都能使用

Lock锁

1.Synchronize和Lock锁的区别?

Synchronize不能手动开锁,Lock需要手动开关锁

2.Lock 搭配Condition  

 private Condition notFull = lock.newCondition();

private Condition notEmpty = lock.newCondition();

notEmpty.await(); //类似于synchronize中的wait

notFull.signal();  //类似于synchronize中的notify

怎样停止线程?

1.使用退出标志,让run运行完后自动终止

2.使用stop方法强行终止(不推荐)

3.使用interrupt终止

0004 java并发编程

 1.有T1,T2,T3三个线程,怎样保证T2在T1执行完后执行,T3在T2执行完后执行?(利用join)

在多线程下,怎样保证主线程最后执行?

public class TestJoin
{
    public static void main(String[] args)
    {
        Thread t1 = new MyThread("线程1");
        Thread t2 = new MyThread("线程2");
        Thread t3 = new MyThread("线程3");
        
        try
        {
            //t1先启动
            t1.start();
            t1.join();
            //t2
            t2.start();
            t2.join();
            //t3
            t3.start();
            t3.join();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}

class MyThread extend Thread{
    public MyThread(String name){
        setName(name);
    }
    @Override
    public void run()
    {
        for (int i = 0; i < 5; i++)
        {
            System.out.println(Thread.currentThread().getName()+": "+i);
            try
            {
                Thread.sleep(100);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
}

 第二节  java内存模型

多线程三大特性:原子性,可见性,有序性

原子性:几个步骤要么全部执行要么全部不执行

可见性:当多个线程访问同一变量,一个线程修改了这个变量的值,其他线程能够立即看到修改的值

有序性:程序执行按照代码先后顺序执行

java内存模型(JMM):多线程

jvm内存结构:堆,栈,方法区

共享内存模型指的是java内存模型(JMM),JMM决定一个线程对共享变量的写入时,能对另一个线程可见

JMM定义了线程和主线程之间的抽象关系,线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存

0000-0010_第2张图片

 

 

 

t1从主内存中获取了变量,修改后还没有更新回主存,然后t2从主内存中获取变量并修改,此时就会出现线程安全问题

第三节 volatile关键字

Volatile 关键字的作用是变量在多个线程之间可见。

代码:

class ThreadVolatileDemo extends Thread {

    public    boolean flag = true;

    @Override

    public void run() {

         System.out.println("开始执行子线程....");

         while (flag) {

         }

         System.out.println("线程停止");

    }

    public void setRuning(boolean flag) {

         this.flag = flag;

    }

 

}

 

public class ThreadVolatile {

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

         ThreadVolatileDemo threadVolatileDemo = new ThreadVolatileDemo();

         threadVolatileDemo.start();//启动的时候把默认的值true,复制到了该线程的本地内存

         Thread.sleep(3000);

         threadVolatileDemo.setRuning(false);  //主线程先从共享内存中复制一份到本地内存,修改为false后会返回给共享内存,但是子线程一直在运行中,没有从共享内存中取最新值过去,所以导致了子线程中的值一直为true
System.out.println("flag 已经设置成false"); Thread.sleep(1000); System.out.println(threadVolatileDemo.flag); } }

  


 运行结果:

 

 

 

已经将结果设置为fasle为什么?还一直在运行呢。

原因:线程之间是不可见的,读取的是副本,没有及时读取到主内存结果。

解决办法使用Volatile关键字将解决线程之间可见性, 强制线程每次读取该值的时候都去“主内存”中取值

第四节 AtomicInteger使用

public class VolatileNoAtomic extends Thread {
	static int count = 0;
	private static AtomicInteger atomicInteger = new AtomicInteger(0);

	@Override
	public void run() {
		for (int i = 0; i < 1000; i++) {
			//等同于i++
			atomicInteger.incrementAndGet();
		}
		System.out.println(count);
	}

	public static void main(String[] args) {
		// 初始化10个线程
		VolatileNoAtomic[] volatileNoAtomic = new VolatileNoAtomic[10];
		for (int i = 0; i < 10; i++) {
			// 创建
			volatileNoAtomic[i] = new VolatileNoAtomic();
		}
		for (int i = 0; i < volatileNoAtomic.length; i++) {
			volatileNoAtomic[i].start();
		}
	}

}

 volatile和synchronize区别? 

仅靠volatile不能保证线程的安全性。(原子性)

①volatile轻量级,只能修饰变量。synchronized重量级,还可修饰方法

②volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。

synchronized不仅保证可见性,而且还保证原子性,因为,只有获得了锁的线程才能进入临界区,从而保证临界区中的所有语句都全部执行。多个线程争抢synchronized锁对象时,会出现阻塞。

 

线程安全性包括两个方面,①可见性。②原子性。

从上面自增的例子中可以看出:仅仅使用volatile并不能保证线程安全性。而synchronized则可实现线程的安全性。

 

第五节 ThreadLocal 

 

ThreadLocal提高一个线程的局部变量,访问某个线程拥有自己局部变量。

 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

ThreadLocal的接口方法

ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:

  • void set(Object value)设置当前线程的线程局部变量的值。
  • public Object get()该方法返回当前线程所对应的线程局部变量。
  • public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
  • protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null
    class Res {
    	// 生成序列号共享变量
    	public static Integer count = 0;
    	public static ThreadLocal threadLocal = new ThreadLocal() {
    		protected Integer initialValue() {
    
    			return 0;
    		};
    
    	};
    
    	public Integer getNum() {
    		int count = threadLocal.get() + 1;
    		threadLocal.set(count);
    		return count;
    	}
    }
    
    public class ThreadLocaDemo2 extends Thread {
    	private Res res;
    
    	public ThreadLocaDemo2(Res res) {
    		this.res = res;
    	}
    
    	@Override
    	public void run() {
    		for (int i = 0; i < 3; i++) {
    			System.out.println(Thread.currentThread().getName() + "---" + "i---" + i + "--num:" + res.getNum());
    		}
    
    	}
    
    	public static void main(String[] args) {
    		Res res = new Res();
    		ThreadLocaDemo2 threadLocaDemo1 = new ThreadLocaDemo2(res);
    		ThreadLocaDemo2 threadLocaDemo2 = new ThreadLocaDemo2(res);
    		ThreadLocaDemo2 threadLocaDemo3 = new ThreadLocaDemo2(res);
    		threadLocaDemo1.start();
    		threadLocaDemo2.start();
    		threadLocaDemo3.start();
    	}
    
    }
    

     实现原理:

  • ThreadLoca通过map集合

    Map.put(“当前线程”,值);

第六节 线程池

Java通过Executors(jdk1.5并发包)提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

newCachedThreadPool:

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
		for (int i = 0; i < 10; i++) {
			final int index = i;
			// try {
			// Thread.sleep(index * 1000);
			// } catch (InterruptedException e) {
			// e.printStackTrace();
			// }
			cachedThreadPool.execute(new Runnable() {
				public void run() {
					System.out.println(Thread.currentThread().getName() + "---" + index);
				}
			});
		}

newFixedThreadPool

创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

// 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
		final ExecutorService newCachedThreadPool = Executors.newFixedThreadPool(3);

		for (int i = 0; i < 10; i++) {
			final int index = i;
			newCachedThreadPool.execute(new Runnable() {
				public void run() {
					try {
						Thread.sleep(1000);
					} catch (Exception e) {
						// TODO: handle exception
					}
					System.out.println("i:" + index);
				}
			});
		}

  

  

总结:因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。

定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()

 

newScheduledThreadPool

// 创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:
		ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(5);
		newScheduledThreadPool.schedule(new Runnable() {
			public void run() {
				System.out.println("delay 3 seconds");
			}
		}, 3, TimeUnit.SECONDS);

 newSingleThreadExecutor

ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
		for (int i = 0; i < 10; i++) {
			final int index = i;
			newSingleThreadExecutor.execute(new Runnable() {

				@Override
				public void run() {
					System.out.println("index:" + index);
					try {
						Thread.sleep(200);
					} catch (Exception e) {
						// TODO: handle exception
					}
				}
			});
		}

 0005 数据交换格式和SpringIOC底层实现

Json(数据格式) Jsonp(跨域)

移动端(安卓、IOS)通讯方式采用http协议+JSON格式 走restful风格。

很多互联网项目都采用Http协议+JSON

因为xml比较重WebService服务采用http+xml格式 银行项目使用比较多

常用json解析框架

fastjson(阿里)、gson(谷歌)、jackson(SpringMVC自带)

使用fastjson解析json

第二节 java反射

什么是Java反射机制?

  在运行期间动态获取这个类的所有信息

应用场景?

  Jdbc加载驱动

  Spring IOC

  框架

反射机制获取类的三种方法:

//第一种方式:  
		Classc1 = Class.forName("Employee");  
		//第二种方式:  
		//java中每个类型都有class 属性.  
		Classc2 = Employee.class;  
		   
		//第三种方式:  
		//java语言中任何一个java对象都有getClass 方法  
		Employeee = new Employee();  
		Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)  	

 第七节  SpringIOC概述

什么是SpringIOC底层实现原理?

1.读取bean的XML配置文件

2.使用beanId查找bean配置,并获取配置文件中class地址。

3.使用Java反射技术实例化对象

4.获取属性配置,使用反射技术进行赋值。

public class ClassPathXmlApplicationContext {
	private String xmlPath;

	/**
	 * 
	 * @param xmlPath
	 *            spring xml 配置路径
	 */
	public ClassPathXmlApplicationContext(String xmlPath) {
		this.xmlPath = xmlPath;
	}

	public Object getBean(String beanId) throws Exception {

		// 解析xml器
		SAXReader saxReader = new SAXReader();
		Document read = null;
		try {
			// 从项目根目录路径下 读取
			read = saxReader.read(this.getClass().getClassLoader().getResourceAsStream(xmlPath));
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (read == null) {
			return null;
		}
		// 获取根节点资源
		Element root = read.getRootElement();
		List elements = root.elements();
		if (elements.size() <= 0) {
			return null;
		}
		Object oj = null;
		for (Element element : elements) {
			String id = element.attributeValue("id");
			if (StringUtils.isEmpty(id)) {
				return null;
			}
			if (!id.equals(beanId)) {
				continue;
				// throw new Exception("使用beanId:" + beanId + ",未找到该bean");
			}
			// 获取实体bean class地址
			String beanClass = element.attributeValue("class");
			// 使用反射实例化bean
			Class forNameClass = Class.forName(beanClass);
			oj = forNameClass.newInstance();
			// 获取子类对象
			List attributes = element.elements();
			if (attributes.size() <= 0) {
				return null;
			}
			for (Element et : attributes) {
				// 使用反射技术为方法赋值
				String name = et.attributeValue("name");
				String value = et.attributeValue("value");
				Field field = forNameClass.getDeclaredField(name);
				field.setAccessible(true);
				field.set(oj, value);

			}

		}
		return oj;
		// 1.使用beanId查找配置文件中的bean。
		// 2.获取对应bean中的classpath配置
		// 3.使用java反射机制实体化对象
	}

	public static void main(String[] args) throws Exception {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"applicationContext.xml");
		User bean = (User) applicationContext.getBean("user2");
		System.out.println("使用反射获取bean" + bean.getUserId() + "---" + bean.getUserName());

	}
}

  

 0006 自定义注解与设计模式

第一节 注解概述与内置注解

什么是注解?

Jdk1.5新增新技术,注解。很多框架为了简化代码,都会提供有些注解。可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件。

注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。

注解分类:内置注解(也成为元注解 jdk 自带注解)、自定义注解(Spring框架)

内置注解:

(1) @SuppressWarnings   在程序前面加上可以在javac编译中去除警告--阶段是SOURCE
(2) @Deprecated   带有标记的包,方法,字段说明其过时----阶段是SOURCE
(3)@Overricle   打上这个标记说明该方法是将父类的方法重写--阶段是SOURCE

 第二节 自定义注解

@Target(value = { ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface OneAnnotation {
int beanId() default 0;
String className() default "";
String[]arrays();
}

使用:
@OneAnnotation(beanId = 123, className = "className", arrays = { "111", "222" })
	public void add() {
	} 

第三节 实现ORM框架映射

@Retention(RetentionPolicy.RUNTIME)
public @interface SetProperty {
	/**
	 * 
	 * @methodDesc: 功能描述:(字段名称)
	 * @author: 余胜军
	 * @param: @return
	 * @createTime:2017年8月27日 上午12:14:02
	 * @returnType:@return String
	 * @copyright:上海每特教育科技有限公司
	 */
	String name();
	/**
	 * 
	 * @methodDesc: 功能描述:(长度)
	 * @author: 余胜军
	 * @param: @return
	 * @createTime:2017年8月27日 上午12:14:25
	 * @returnType:@return int
	 * @copyright:上海每特教育科技有限公司
	 */
	int leng();
}


public class Main {

	public static void main(String[] args) throws ClassNotFoundException {
		// 1.反射class
		Class classForName = Class.forName("com.entity.Sudent");
		// 2.获取表名称注解F
		SetTable setTable = classForName.getAnnotation(SetTable.class);
		// 3.获取所有的成员属性
		Field[] declaredFields = classForName.getDeclaredFields();
		StringBuffer sf = new StringBuffer();
		sf.append(" select ");
		String fromName = setTable.value();
		for (int i = 0; i < declaredFields.length; i++) {
			Field field = declaredFields[i];
			// 4.属性字段
			SetProperty sb = field.getAnnotation(SetProperty.class);
			sf.append(" " + sb.name() + " ");
			if (i == declaredFields.length - 1) {
				sf.append(" from ");
			} else {
				sf.append(" , ");
			}
		}
		sf.append(" " + fromName);
		System.out.println(sf.toString());
	}

} 

 第四节 常用设计模式

单例模式:保证一个对象在JVM中只能有一个实例,常见单例 懒汉式  饿汉式

懒汉式:需要的时候才去实例化,线程不安全

饿汉式:当class文件被加载的时候,初始化,天生线程安全

懒汉式:

public classSingleton{

  private static Singleton singleton;

       //构造器私有化,不让外界初始化

       private Singleton(){

 

  }

  //由于线程不安全,则加上

  public static synchronized Singleton getSingleton(){

    if(singleton == null){

      singleton = new Singleton();

    }

    return singleton;

  }

}

 

饿汉式:

public class Singleton{

  //在类加载时就初始化了,天生线程安全

  private static final Singleton singleton=new Singleton();

        private Singleton(){

 

  }

  public static Singleton getSingleton(){

    return singleton;

  }

}

 

工厂模式:

public interface Car {
	public void run();
}
public class AoDi implements Car {
	@Override
	public void run() {
     System.out.println("奥迪....");
	}
}
public class BenChi implements Car {
	@Override
	public void run() {
     System.out.println("奔驰....");
	}
}

public class CarFactory {
	static public Car createCar(String carName) {
		Car car = null;
		if (carName.equals("奥迪")) {
			car = new AoDi();
		} else if (carName.equals("奔驰")) {
			car = new BenChi();
		}
		return car;

	}
	public static void main(String[] args) {
		Car car1 = CarFactory.createCar("奥迪");
		Car car2 = CarFactory.createCar("奔驰");
		car1.run();
		car2.run();
	}
}

代理模式:

静态代理:

public class XiaoMing implements Hose {
	@Override
	public void mai() {
		System.out.println("我是小明,我要买房啦!!!!haha ");
	}
}
class Proxy  implements Hose {
	private XiaoMing xiaoMing;
	public Proxy(XiaoMing xiaoMing) {
		this.xiaoMing = xiaoMing;
	}
	public void mai() {
		System.out.println("我是中介 看你买房开始啦!");
		xiaoMing.mai();
		System.out.println("我是中介 看你买房结束啦!");
	}
	public static void main(String[] args) {
		Hose proxy = new Proxy(new XiaoMing());
		proxy.mai();
	}
}

 jdk动态代理:jdk使用反射原理生成代理类

public interface Hose {


	public void mai();

}


public class XiaoMing implements Hose {

	@Override
	public void mai() {
		System.out.println("我是小明,我要买房啦!!!!haha ");
	}

}

public class JDKProxy implements InvocationHandler {
	private Object tarjet;

	public JDKProxy(Object tarjet) {
		this.tarjet = tarjet;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("我是房产中介.....开始监听你买房啦!");
		Object oj = method.invoke(tarjet, args);
		System.out.println("我是房产中介.....结束监听你买房啦!");
		return oj;

	}

}

class Test222 {
	public static void main(String[] args) {
		XiaoMing xiaoMing = new XiaoMing();
		JDKProxy jdkProxy = new JDKProxy(xiaoMing);
		Hose hose=(Hose) Proxy.newProxyInstance(xiaoMing.getClass().getClassLoader(), xiaoMing.getClass().getInterfaces(), jdkProxy);
		hose.mai();
	}

}

 

CGLIB代理:

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class Cglib implements MethodInterceptor {

	@Override
	public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		System.out.println("我是买房中介 , 开始监听你买房了....");
		Object invokeSuper = methodProxy.invokeSuper(o, args);
		System.out.println("我是买房中介 , 开结束你买房了....");
		return invokeSuper;

	}

}

class Test22222 {
	public static void main(String[] args) {
		Cglib cglib = new Cglib();
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(XiaoMing.class);
		enhancer.setCallback(cglib);
		Hose hose = (Hose) enhancer.create();
		hose.mai();
	}
}

  

jdk动态代理是由Java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。

注:asm其实就是java字节码控制.

总结: 代理分两种,一种是静态代理,一种是动态代理

其中动态代理分为jdk动态代理和Cglib动态代理

jdk动态代理底层是用反射实现,Cglib动态代理使用Asm框架

SpringAop底层实现是用Cglib动态代理

0007 Java网络编程

第一节 Socket

1.网络模型

 

2.TCP协议与UDP协议区别

tcp: a、建议连接,形成传输数据的通道.

    b、在连接中进行大数据量传输,以字节流方式

    c 通过三次握手完成连接,是可靠协议

    d 必须建立连接,效率会稍低

udp: a、是面向无连接, 将数据及源的封装成数据包中,不需要建立建立连接

    b、每个数据报的大小在限制64k内

    c、因无连接,是不可靠协议

    d、不需要建立连接,速度快

 

 

 

3.Http底层实现原理

 网络模型图

0000-0010_第3张图片

 

 TCP三次握手过程:

在TCP/IP协议中,TCP协议采用三次握手建立一个连接。 
第一次握手:建立连接时,客户端发送SYN包(SYN=J)到服务器,并进入SYN_SEND状态,等待服务器确认; 
第二次握手:服务器收到SYN包,必须确认客户的SYN(ACK=J+1),同时自己也发送一个SYN包(SYN=K),即SYN+ACK包,此时服务器V状态; 
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ACK=K+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据,

 0000-0010_第4张图片

 

 

四次分手:
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。

 0000-0010_第5张图片

 

 

1.为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
    这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在 一个报文里来发送。

但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以 未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报 文和FIN报文多数情况下都是分开发送的.

2.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。

 0010 深入理解Servlet

1.Servlet生命周期

构造方法: 创建servlet对象的时候调用。默认情况下,第一次访问servlet的时候创建servlet对象                                                   只调用1次。证明servlet对象在tomcat是单实例的。

                        init方法: 创建完servlet对象的时候调用。只调用1次。

                        service方法: 每次发出请求时调用。调用n次。

                        destroy方法: 销毁servlet对象的时候调用。停止服务器或者重新部署web应用时销毁servlet对象。

                                                        只调用1次。

 

 Servlet默认是单例,在请求访问时才创建,属于懒汉式单例

Servle生命周期

Tomtcat内部代码运行:
			1)通过映射找到到servlet-class的内容,字符串: com.itmayiedu.a_servlet.FirstServlet
			2)通过反射构造FirstServlet对象
					2.1 得到字节码对象
					Class clazz = class.forName("com.itmayiedu.a_servlet.FirstServlet");
					2.2 调用无参数的构造方法来构造对象
					Object obj = clazz.newInstance();     ---1.servlet的构造方法被调用
			3)创建ServletConfig对象,通过反射调用init方法
					3.1 得到方法对象
					Method m = clazz.getDeclareMethod("init",ServletConfig.class);
					3.2 调用方法
					m.invoke(obj,config);             --2.servlet的init方法被调用
			4)创建request,response对象,通过反射调用service方法
					4.1 得到方法对象
					Methodm m =clazz.getDeclareMethod("service",HttpServletRequest.class,HttpServletResponse.class);
					4.2 调用方法
					m.invoke(obj,request,response);  --3.servlet的service方法被调用
			5)当tomcat服务器停止或web应用重新部署,通过反射调用destroy方法
					5.1 得到方法对象
					Method m = clazz.getDeclareMethod("destroy",null);
					5.2 调用方法
					m.invoke(obj,null);            --4.servlet的destroy方法被调用

 

 0000-0010_第6张图片

如果init方法初始化东西过多,第一次访问会很慢,所以需要将Servlet在启动时马上初始化:

    LifeDemo

    com.itmayiedu.life.LifeDemo

   

    1  注意: 整数值越大,创建优先级越低!!

  、

Servlet 多线程安全问题

 线程安全代码:

package com.servlet;

import java.io.IOException;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServetlDemo4 extends HttpServlet {
	private int i = 1;

	@Override
	public void init() throws ServletException {
		System.out.println("ServetlDemo4...init()");
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		// 设置编码格式
		// resp.setContentType("text/html;charset=utf-8");
		resp.setCharacterEncoding("utf-8");// 内容编码,防止出现中文乱码
		resp.setContentType("text/html;charset=utf-8");
		synchronized (ServetlDemo4.class) {
			// 向浏览器输出内容
			resp.getWriter().write("这是第" + i + "次访问...");
			try {
				Thread.sleep(5000);
			} catch (Exception e) {
				// TODO: handle exception
			}

			i++;
		}

	}

	@Override
	public void destroy() {
		System.out.println("ServetlDemo4...destroy()");

	}

}

  

你可能感兴趣的:(0000-0010)