diff --git a/Java/JDK阅读/java.md b/Java/JDK阅读/java.md new file mode 100644 index 00000000..0f14c074 --- /dev/null +++ b/Java/JDK阅读/java.md @@ -0,0 +1,2 @@ +\| +具体应该参考相应的jdk进行,了解相应的方法。这里只说明类的主要作用,和自己的相关理解,以及部分常用的方法。 diff --git a/Java/JDK阅读/java.thread.md b/Java/JDK阅读/java.thread.md new file mode 100644 index 00000000..0a3c119a --- /dev/null +++ b/Java/JDK阅读/java.thread.md @@ -0,0 +1,370 @@ +**引** + +如果对什么是线程、什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内。 + +用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”。 + +很多人都对其中的一些概念不够明确,如同步、并发等等,让我们先建立一个数据字典,以免产生误会。 + +- 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程 + +- 并行与并发: + + - 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。 + + - 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。 + +![a468b2694253.png](media/7932f8d9c5acc2d3a1896b4c3233612e.png) + +并发与并行 + +- 线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果,如不加事务的转账代码: + +void transferMoney(User from, User to, float amount){ +to.setMoney(to.getBalance() + amount); from.setMoney(from.getBalance() - +amount); } + +- 同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码简单加入@synchronized关键字。在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能。 + +好了,让我们开始吧。我准备分成几部分来总结涉及到多线程的内容: + +1. 扎好马步:线程的状态 + +2. 内功心法:每个对象都有的方法(机制) + +3. 太祖长拳:基本线程类 + +4. 九阴真经:高级多线程控制类 + +**扎好马步:线程的状态** + +先来两张图: + +![5b75b44e972c.png](media/c5008c69466298cf4ed608e4f6b569f0.png) + +线程状态 + +![7101e6588094.png](media/995e20b243fa0e000d51589ebb780e75.png) + +线程状态转换 + +各种状态一目了然,值得一提的是"blocked"这个状态: + +线程在Running的过程中可能会遇到阻塞(Blocked)情况 + +1. 调用join()和sleep()方法,sleep()时间结束或被打断,join()中断,IO完成都会回到Runnable状态,等待JVM的调度。 + +2. 调用wait(),使该线程处于等待池(wait blocked + pool),直到notify()/notifyAll(),线程被唤醒被放到锁定池(lock blocked pool + ),释放同步锁使线程回到可运行状态(Runnable) + +3. 对Running状态的线程加同步锁(Synchronized)使其进入(lock blocked pool + ),同步锁被释放进入可运行状态(Runnable)。 + +此外,在runnable状态的线程是处于被调度的线程,此时的调度顺序是不一定的。Thread类中的yield方法可以让一个running状态的线程转入runnable。 + +**内功心法:每个对象都有的方法(机制)** + +synchronized, wait, notify 是任何对象都具有的同步工具。让我们先来了解他们 + +![0771d68cb2ba.png](media/51d56de3dfb3391d64c34cc5121e3bd0.png) + +monitor + +他们是应用于同步问题的人工线程调度工具。讲其本质,首先就要明确monitor的概念,Java中的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronized +范围内,监视器发挥作用。 + +wait/notify必须存在于synchronized块中。并且,这三个关键字针对的是同一个监视器(某对象的监视器)。这意味着wait之后,其他线程可以进入同步块执行。 + +当某代码并不持有监视器的使用权时(如图中5的状态,即脱离同步块)去wait或notify,会抛出java.lang.IllegalMonitorStateException。也包括在synchronized块中去调用另一个对象的wait/notify,因为不同对象的监视器不同,同样会抛出此异常。 + +再讲用法: + +- synchronized单独使用: + + - 代码块:如下,在多线程环境下,synchronized块中的方法获取了lock实例的monitor,如果实例相同,那么只有一个线程能执行该块内容 + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +public class Thread1 implements Runnable { Object lock; public void run() { +synchronized(lock){ ..do something } } } + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +- 直接用于方法: + 相当于上面代码中用lock来锁定的效果,实际获取的是Thread1类的monitor。更进一步,如果修饰的是static方法,则锁定该类所有实例。 + +public class Thread1 implements Runnable { public synchronized void run() { ..do +something } } + +- synchronized, wait, notify结合:典型场景生产者消费者问题 + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +/\*\* \* 生产者生产出来的产品交给店员 \*/ public synchronized void produce() { +if(this.product \>= MAX_PRODUCT) { try { wait(); +System.out.println("产品已满,请稍候再生产"); } catch(InterruptedException e) { +e.printStackTrace(); } return; } this.product++; +System.out.println("生产者生产第" + this.product + "个产品."); notifyAll(); +//通知等待区的消费者可以取出产品了 } /\*\* \* 消费者从店员取产品 \*/ public +synchronized void consume() { if(this.product \<= MIN_PRODUCT) { try { wait(); +System.out.println("缺货,稍候再取"); } catch (InterruptedException e) { +e.printStackTrace(); } return; } System.out.println("消费者取走了第" + +this.product + "个产品."); this.product--; notifyAll(); +//通知等待去的生产者可以生产产品了} + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +**volatile** + +多线程的内存模型:main memory(主存)、working +memory(线程栈),在处理数据时,线程会把值从主存load到本地栈,完成操作后再save回去(volatile关键词的作用:每次针对该变量的操作都激发一次load +and save)。 + +![6cfda7042c67.png](media/54db549dedb71c1ac0e24d21fa81faf4.png) + +volatile + +针对多线程使用的变量如果不是volatile或者final修饰的,很有可能产生不可预知的结果(另一个线程修改了这个值,但是之后在某线程看到的是修改之前的值)。其实道理上讲同一实例的同一属性本身只有一个副本。但是多线程是会缓存值的,本质上,volatile就是不去缓存,直接取值。在线程安全的情况下加volatile会牺牲性能。 + +**太祖长拳:基本线程类** + +基本线程类指的是Thread类,Runnable接口,Callable接口 + +Thread 类实现了Runnable接口,启动一个线程的方法: + +MyThread my = new MyThread(); my.start(); + +**Thread类相关方法:** + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +//当前线程可转让cpu控制权,让别的就绪状态线程运行(切换)public static +Thread.yield() //暂停一段时间public static Thread.sleep() +//在一个线程中调用other.join(),将等待other执行完后才继续本线程。 public join() +//后两个函数皆可以被打断public interrupte() + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +**关于中断**:它并不像stop方法那样会中断一个正在运行的线程。线程会不时地检测中断标识位,以判断线程是否应该被中断(中断标识值是否为true)。终端只会影响到wait状态、sleep状态和join状态。被打断的线程会抛出InterruptedException。 + +Thread.interrupted()检查当前线程是否发生中断,返回boolean + +synchronized在获锁的过程中是不能被中断的。 + +中断是一个状态!interrupt()方法只是将这个状态置为true而已。所以说正常运行的程序不去检测状态,就不会终止,而wait等阻塞方法会去检查并抛出异常。如果在正常运行的程序中添加while(!Thread.interrupted()) +,则同样可以在中断后离开代码体 + +**Thread类最佳实践**: + +写的时候最好要设置线程名称 Thread.name,并设置线程组 +ThreadGroup,目的是方便管理。在出现问题的时候,打印线程栈 (jstack -pid) +一眼就可以看出是哪个线程出的问题,这个线程是干什么的。 + +**如何获取线程中的异常** + +![5b7f8df6e8d3.png](media/429f749d3870e8c9a198746da0d0ca6e.png) + +不能用try,catch来获取线程中的异常 + +**Runnable** + +与Thread类似 + +**Callable** + +future模式:并发模式的一种,可以有两种形式,即无阻塞和阻塞,分别是isDone和get。其中Future对象用来存放该线程的返回值以及状态 + +ExecutorService e = Executors.newFixedThreadPool(3); +//submit方法有多重参数版本,及支持callable也能够支持runnable接口类型.Future +future = e.submit(new myCallable()); future.isDone() //return true,false 无阻塞 +future.get() // return 返回值,阻塞直到该线程运行结束 + +**九阴真经:高级多线程控制类** + +以上都属于内功心法,接下来是实际项目中常用到的工具了,Java1.5提供了一个非常高效实用的多线程包:*java.util.concurrent*, +提供了大量高级工具,可以帮助开发者编写高效、易维护、结构清晰的Java多线程程序。 + +**1.ThreadLocal类** + +用处:保存线程的独立变量。对一个线程类(继承自Thread) + +当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。常用于用户登录控制,如记录session信息。 + +实现:每个Thread都持有一个TreadLocalMap类型的变量(该类是一个轻量级的Map,功能与map一样,区别是桶里放的是entry而不是entry的链表。功能还是一个map。)以本身为key,以目标为value。 + +主要方法是get()和set(T a),set之后在map里维护一个threadLocal -\> +a,get时将a返回。ThreadLocal是一个特殊的容器。 + +**2.原子类(AtomicInteger、AtomicBoolean……)** + +如果使用atomic wrapper +class如atomicInteger,或者使用自己保证原子的操作,则等同于synchronized + +//返回值为booleanAtomicInteger.compareAndSet(int expect,int update) + +该方法可用于实现乐观锁,考虑文中最初提到的如下场景:a给b付款10元,a扣了10元,b要加10元。此时c给b2元,但是b的加十元代码约为: + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +if(b.value.compareAndSet(old, value)){ return ; }else{ //try again // if that +fails, rollback and log} + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +**AtomicReference** + +对于AtomicReference 来讲,也许对象会出现,属性丢失的情况,即oldObject == +current,但是oldObject.getPropertyA != current.getPropertyA。 + +这时候,AtomicStampedReference就派上用场了。这也是一个很常用的思路,即加上版本号 + +**3.Lock类** + +lock: 在java.util.concurrent包内。共有三个实现: + +ReentrantLock ReentrantReadWriteLock.ReadLock ReentrantReadWriteLock.WriteLock + +主要目的是和synchronized一样, +两者都是为了解决同步问题,处理资源争端而产生的技术。功能类似但有一些区别。 + +区别如下: + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +lock更灵活,可以自由定义多把锁的枷锁解锁顺序(synchronized要按照先加的后解顺序) +提供多种加锁方案,lock 阻塞式, trylock 无阻塞式, lockInterruptily 可打断式, +还有trylock的带超时时间版本。 本质上和监视器锁(即synchronized是一样的) +能力越大,责任越大,必须控制好加锁和解锁,否则会导致灾难。 和Condition类的结合。 +性能更高,对比如下图: + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +![93b31bfed934.png](media/4c9b2a5287c91f386c9db0ba1920904b.png) + +synchronized和Lock性能对比 + +**ReentrantLock** + +可重入的意义在于持有锁的线程可以继续持有,并且要释放对等的次数后才真正释放该锁。 + +使用方法是: + +1.先new一个实例 + +static ReentrantLock r=new ReentrantLock(); + +2.加锁 + +r.lock()或r.lockInterruptibly(); + +此处也是个不同,后者可被打断。当a线程lock后,b线程阻塞,此时如果是lockInterruptibly,那么在调用b.interrupt()之后,b线程退出阻塞,并放弃对资源的争抢,进入catch块。(如果使用后者,必须throw +interruptable exception 或catch) + +3.释放锁 + +r.unlock() + +必须做!何为必须做呢,要放在finally里面。以防止异常跳出了正常流程,导致灾难。这里补充一个小知识点,finally是可以信任的:经过测试,哪怕是发生了OutofMemoryError,finally块中的语句执行也能够得到保证。 + +**ReentrantReadWriteLock** + +可重入读写锁(读写锁的一个实现) + +ReentrantReadWriteLock lock = new ReentrantReadWriteLock() ReadLock r = +lock.readLock(); WriteLock w = lock.writeLock(); + +两者都有lock,unlock方法。写写,写读互斥;读读不互斥。可以实现并发读的高效线程安全代码 + +**4.容器类** + +这里就讨论比较常用的两个: + +BlockingQueue ConcurrentHashMap + +**BlockingQueue** + +阻塞队列。该类是java.util.concurrent包下的重要类,通过对Queue的学习可以得知,这个queue是单向队列,可以在队列头添加元素和在队尾删除或取出元素。类似于一个管 +道,特别适用于先进先出策略的一些应用场景。普通的queue接口主要实现有PriorityQueue(优先队列),有兴趣可以研究 + +BlockingQueue在队列的基础上添加了多线程协作的功能: + +![7b06b8d86db8.png](media/6cb91c2845273c5693a564bab023d4e3.png) + +BlockingQueue + +除了传统的queue功能(表格左边的两列)之外,还提供了阻塞接口put和take,带超时功能的阻塞接口offer和poll。put会在队列满的时候阻塞,直到有空间时被唤醒;take在队 +列空的时候阻塞,直到有东西拿的时候才被唤醒。用于生产者-消费者模型尤其好用,堪称神器。 + +常见的阻塞队列有: + +ArrayListBlockingQueue LinkedListBlockingQueue DelayQueue SynchronousQueue + +**ConcurrentHashMap** + +高效的线程安全哈希map。请对比hashTable , concurrentHashMap, HashMap + +**5.管理类** + +管理类的概念比较泛,用于管理线程,本身不是多线程的,但提供了一些机制来利用上述的工具做一些封装。 + +了解到的值得一提的管理类:ThreadPoolExecutor和 JMX框架下的系统级管理类 +ThreadMXBean + +**ThreadPoolExecutor** + +如果不了解这个类,应该了解前面提到的ExecutorService,开一个自己的线程池非常方便: + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +ExecutorService e = Executors.newCachedThreadPool(); ExecutorService e = +Executors.newSingleThreadExecutor(); ExecutorService e = +Executors.newFixedThreadPool(3); // +第一种是可变大小线程池,按照任务数来分配线程, // +第二种是单线程池,相当于FixedThreadPool(1) // 第三种是固定大小线程池。 // +然后运行e.execute(new MyRunnableImpl()); + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +该类内部是通过ThreadPoolExecutor实现的,掌握该类有助于理解线程池的管理,本质上,他们都是ThreadPoolExecutor类的各种实现版本。请参见javadoc: + +![8a70ba646843.png](media/ec7fd9666c2bd70bfc26c6c2a1f7538a.png) + +ThreadPoolExecutor参数解释 + +翻译一下: + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +corePoolSize:池内线程初始值与最小值,就算是空闲状态,也会保持该数量线程。 +maximumPoolSize:线程最大值,线程的增长始终不会超过该值。 +keepAliveTime:当池内线程数高于corePoolSize时,经过多少时间多余的空闲线程才会被回收。回收前处于wait状态 +unit: 时间单位,可以使用TimeUnit的实例,如TimeUnit.MILLISECONDS +workQueue:待入任务(Runnable)的等待场所,该参数主要影响调度策略,如公平与否,是否产生饿死(starving) +threadFactory:线程工厂类,有默认实现,如果有自定义的需要则需要自己实现ThreadFactory接口并作为参数传入。 diff --git a/Java/JDK阅读/jdk阅读笔记说明.md b/Java/JDK阅读/jdk阅读笔记说明.md new file mode 100644 index 00000000..f63bd660 --- /dev/null +++ b/Java/JDK阅读/jdk阅读笔记说明.md @@ -0,0 +1 @@ +以功能为单位进行记录。主要说明实现某个具体功能时用到的相关类。以及类的主要用法。 diff --git a/Java/JDK阅读/media/429f749d3870e8c9a198746da0d0ca6e.png b/Java/JDK阅读/media/429f749d3870e8c9a198746da0d0ca6e.png new file mode 100644 index 00000000..3bb640b5 Binary files /dev/null and b/Java/JDK阅读/media/429f749d3870e8c9a198746da0d0ca6e.png differ diff --git a/Java/JDK阅读/media/4c9b2a5287c91f386c9db0ba1920904b.png b/Java/JDK阅读/media/4c9b2a5287c91f386c9db0ba1920904b.png new file mode 100644 index 00000000..dc3f06c9 Binary files /dev/null and b/Java/JDK阅读/media/4c9b2a5287c91f386c9db0ba1920904b.png differ diff --git a/Java/JDK阅读/media/51d56de3dfb3391d64c34cc5121e3bd0.png b/Java/JDK阅读/media/51d56de3dfb3391d64c34cc5121e3bd0.png new file mode 100644 index 00000000..b8c8eea6 Binary files /dev/null and b/Java/JDK阅读/media/51d56de3dfb3391d64c34cc5121e3bd0.png differ diff --git a/Java/JDK阅读/media/51e409b11aa51c150090697429a953ed.gif b/Java/JDK阅读/media/51e409b11aa51c150090697429a953ed.gif new file mode 100644 index 00000000..dc146865 Binary files /dev/null and b/Java/JDK阅读/media/51e409b11aa51c150090697429a953ed.gif differ diff --git a/Java/JDK阅读/media/54db549dedb71c1ac0e24d21fa81faf4.png b/Java/JDK阅读/media/54db549dedb71c1ac0e24d21fa81faf4.png new file mode 100644 index 00000000..2f995ee0 Binary files /dev/null and b/Java/JDK阅读/media/54db549dedb71c1ac0e24d21fa81faf4.png differ diff --git a/Java/JDK阅读/media/6cb91c2845273c5693a564bab023d4e3.png b/Java/JDK阅读/media/6cb91c2845273c5693a564bab023d4e3.png new file mode 100644 index 00000000..fc30c8fe Binary files /dev/null and b/Java/JDK阅读/media/6cb91c2845273c5693a564bab023d4e3.png differ diff --git a/Java/JDK阅读/media/7932f8d9c5acc2d3a1896b4c3233612e.png b/Java/JDK阅读/media/7932f8d9c5acc2d3a1896b4c3233612e.png new file mode 100644 index 00000000..5b332deb Binary files /dev/null and b/Java/JDK阅读/media/7932f8d9c5acc2d3a1896b4c3233612e.png differ diff --git a/Java/JDK阅读/media/995e20b243fa0e000d51589ebb780e75.png b/Java/JDK阅读/media/995e20b243fa0e000d51589ebb780e75.png new file mode 100644 index 00000000..6636b488 Binary files /dev/null and b/Java/JDK阅读/media/995e20b243fa0e000d51589ebb780e75.png differ diff --git a/Java/JDK阅读/media/c5008c69466298cf4ed608e4f6b569f0.png b/Java/JDK阅读/media/c5008c69466298cf4ed608e4f6b569f0.png new file mode 100644 index 00000000..4cbe7a9b Binary files /dev/null and b/Java/JDK阅读/media/c5008c69466298cf4ed608e4f6b569f0.png differ diff --git a/Java/JDK阅读/media/ec7fd9666c2bd70bfc26c6c2a1f7538a.png b/Java/JDK阅读/media/ec7fd9666c2bd70bfc26c6c2a1f7538a.png new file mode 100644 index 00000000..3ce5538d Binary files /dev/null and b/Java/JDK阅读/media/ec7fd9666c2bd70bfc26c6c2a1f7538a.png differ diff --git a/Java/JavaEE企业级开发/DAO模式的理解.md b/Java/JavaEE企业级开发/DAO模式的理解.md new file mode 100644 index 00000000..509ac012 --- /dev/null +++ b/Java/JavaEE企业级开发/DAO模式的理解.md @@ -0,0 +1,56 @@ +# DAO模式的原理说明 + +DAO(Data Access +Object)是一个数据访问接口,数据访问:顾名思义就是与数据库打交道,夹在业务逻辑与数据库资源中间。 + +在核心J2EE模式中DAO的定义是:为了建立一个健壮的J2EE应用,应该将所有对数据源的访问操作抽象封装在一个公共API中。用程序设计的语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口在逻辑上对应这个特定的数据存储。 + +DAO层本质上就是MVC中的Model部分的具体实现。相当于整个工程的javabean,实现了对数据库的增删查改。 + +![dao.jpg](media/896ddc649ace2c4d5b318d11c887ece9.jpeg) + +# DAO模式的具体实现 + +\-VO类:提供javabean,表示数据库中的一条记录,主要有getter和setter方法 + +\-DAO类:提供了DAOmodel的接口,供控制器调用 + +\-DAOimplement:实现了DAO类提供的外部接口,主要是通过jdbc链接数据库,实现了数据库的增删查改操作。 + +\-DAOFactory:通过工厂类,获取一个DAO的实例化对象。 + +在当前的工程中分别对应一下包: + +.domain + +.dao + +.dao.impl + +.service.impl + +这四个类分别代daobean,dao接口,dao的jdbc实现,dao的工厂类,在这里实现工程需要的所有的数据库的操作,提供给其他部分调用。 + +最根本的事通过jdbcUtils提供了访问数据库的链接 + +逻辑结构非常清晰明显 + +# 最后说明dao的工作原理 + +![dao2.jpg](media/0df06acb323561f7014fed6f60125206.jpeg) + +关于到的层级在此说明 + +数据库数据存储 + +\|-jdbc提供数据库的链接 + +\|-daoBean数据保存 + +\|-daoImpl的具体实现 + +\|-dao提供数据库访问的接口 + +\|-daoFactory实例化数据库的接口提供具体的数据操作 + +控制器数据操作需求 diff --git a/Java/JavaEE企业级开发/JAVA中库的理解.md b/Java/JavaEE企业级开发/JAVA中库的理解.md new file mode 100644 index 00000000..ff6704be --- /dev/null +++ b/Java/JavaEE企业级开发/JAVA中库的理解.md @@ -0,0 +1,9 @@ +java本身就是一个依赖各种库来构建工程的语言,实际上需要自己写的东西并不多,就是调用各种已经编辑好的库,来实现各自的功能。 + +大部分库都是由jre/jdk内部自带的java库提供的。包括各种不同的版本,导入的时候必须要注意,可能是1.6,1.7,1.8等。 + +在做javaEE开发过程中,部分依赖的网络编程的库org.apache.\*是由Tomcat服务器插件提供的 + +在实现软件测试的过程中,junit4相关的库是由第三方插件提供,也就是说,在构建工程的时候,下载了eclemma插件,提供了org.junit.\*库和junit.\*库。并且提供了net.mooctest.plugin.\*库,实现与mooctest的网站的交互。 + +所以在构建工程过程中,必须得考虑相关库的导入。可能是来自于jdk/jre的官方标准库,也可能是来自于其他特定功能的库(tomcat),也许是来自相关插件的库(如adt插件、eclemma插件、junit4插件)等。 diff --git a/Java/JavaEE企业级开发/JAVA代码组织.md b/Java/JavaEE企业级开发/JAVA代码组织.md new file mode 100644 index 00000000..a9b9c276 --- /dev/null +++ b/Java/JavaEE企业级开发/JAVA代码组织.md @@ -0,0 +1,15 @@ +服务器端: + +java Servlet + +资源配置文件 + +与前端结合: + +jsp:java脚本,直接在前端页面jsp嵌入前端脚本实现动态化。 + +jsp:jsp标签,使用jsp标签来实现基础的控制 + +jsp:EL表达式,使用简化的表达式实现动态数据获取 + +jsp:tag标签,包括标准标签库和自定义标签库的使用。 diff --git a/Java/JavaEE企业级开发/JSP代码作用.md b/Java/JavaEE企业级开发/JSP代码作用.md new file mode 100644 index 00000000..69b00f95 --- /dev/null +++ b/Java/JavaEE企业级开发/JSP代码作用.md @@ -0,0 +1,11 @@ +jsp代码编写属于后端,因为前端开发看不懂JSP代码,他们追求的是网页效果。而JSP其实就是JAVA代码来拼接前端页面而已,本身也是Servlet,因此JAVA +WEB工程师也要学习一些HTML,JS,CSS等,实际开法中前端工程师写好网页,Java +web开发人员负责填写JSP脚本,也可以反过来,后端定义好标签库,让前端以标签的方式来写代码。但近年来,大部分项目都是用Ajax来调用后端接口了,做到前后分离,直接写JSP的少了。 + +作者:清浅池塘 + +链接:https://www.zhihu.com/question/52695070/answer/228804504 + +来源:知乎 + +著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 diff --git a/Java/JavaEE企业级开发/JSP技术详解.md b/Java/JavaEE企业级开发/JSP技术详解.md new file mode 100644 index 00000000..fb8b71b5 --- /dev/null +++ b/Java/JavaEE企业级开发/JSP技术详解.md @@ -0,0 +1,11 @@ +## JSP的内置对象 + +request对象 + +通过from表单能够发送GET和POST方法的Request。 + +request.getParameter("name"):得到键值对的值 + +request.setCharacterEncoding(utf-8);解决编码问题 + +getProtocol diff --git a/Java/JavaEE企业级开发/computer.py b/Java/JavaEE企业级开发/computer.py new file mode 100644 index 00000000..69816475 --- /dev/null +++ b/Java/JavaEE企业级开发/computer.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +import queue +import re +import urllib2 +import time +import urllib2 +headers=("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36") +opener=urllib2.build_opener() +opener.addheaders=[headers] +#global the opener +urllib2.install_opener(opener) +listurl=[] + +#use the procy server +def use_proxy(proxy_addr,url): + try: + import urllib2 + data = urllib2.urlopen(url).read().decode('utf-8') + return data + except urllib2.URLError as e: + if hasattr(e,"code"): + print(e.code) + if hasattr(e,"reason"): + print(e.reason) + time.sleep(10) + except Exception as e: + print("exception:"+str(e)) + time.sleep(1) +# get the picture +def craw(url,number): + html1=urllib2.urlopen(url).read().decode('utf-8') + html1=html1 + pat1='(.*?)' + result1=re.compile(pat1,re.S).findall(html1) + result1=result1[0] + pat2=' + + + +computer + +''' + fh=open("E:/hello/2.html","wb") + fh.write(html1.encode("utf-8")) + fh.close() + fh=open("E:/hello/2.html","ab") + for i in range(0,len(listurl)): + for j in range(0,len(listurl[i])): + try: + url=listurl[i][j] + url=url.replace("\"","") + url = url.replace('../', "") + url="http://jsj.nwpu.edu.cn/"+url + data2=use_proxy(proxy,url) + craw(url,j) + titlepat='(.*?)' + contentpat='(.*?)' + title=re.compile(titlepat).findall(data2) + content=re.compile(contentpat,re.S).findall(data2) + thistitle=" " + thiscontent=" " + + if(title!=[]): + thistitle=title[0] + if(content!=[]): + thiscontent=content[0] + dataall="

title is :"+thistitle+"

content is :"+thiscontent+"


" + fh.write(dataall.encode("utf-8")) + print("第"+str(i)+"第个网站"+str(j)+"次处理") + except urllib2.URLError as e: + if hasattr(e, "code"): + print(e.code) + if hasattr(e, "reason"): + print(e.reason) + time.sleep(10) + except Exception as e: + print("exception:" + str(e)) + time.sleep(1) + fh.close() + html2=''' + + ''' + fh=open("E:/hello/2.html","ab") + fh.write(html2.encode("utf-8")) + fh.close() + +proxy="123.145.128.139:8118" +pagestart=1 +pageend=2 + +url="http://jsj.nwpu.edu.cn/index/xyxw.htm" +data1=use_proxy(proxy,url) +listurlpat='关闭数据库操作对象--\>关闭连接)。 + +**[java]** [view plain](http://blog.csdn.net/hpu_a/article/details/51354867) +[copy](http://blog.csdn.net/hpu_a/article/details/51354867) + +1. **package** com.yangshengjie.jdbc; + +2. **import** java.sql.Connection; + +3. **import** java.sql.DriverManager; + +4. **import** java.sql.ResultSet; + +5. **import** java.sql.SQLException; + +6. **import** java.sql.Statement; + +7. + +8. **public** **class** JDBCTest { + +9. /\*\* + +10. \* 使用JDBC连接并操作mysql数据库 + +11. \*/ + +12. **public** **static** **void** main(String[] args) { + +13. // 数据库驱动类名的字符串 + +14. String driver = "com.mysql.jdbc.Driver"; + +15. // 数据库连接串 + +16. String url = "jdbc:mysql://127.0.0.1:3306/jdbctest"; + +17. // 用户名 + +18. String username = "root"; + +19. // 密码 + +20. String password = "mysqladmin"; + +21. Connection conn = **null**; + +22. Statement stmt = **null**; + +23. ResultSet rs = **null**; + +24. **try** { + +25. // 1、加载数据库驱动( + 成功加载后,会将Driver类的实例注册到DriverManager类中) + +26. Class.forName(driver ); + +27. // 2、获取数据库连接 + +28. conn = DriverManager.getConnection(url, username, password); + +29. // 3、获取数据库操作对象 + +30. stmt = conn.createStatement(); + +31. // 4、定义操作的SQL语句 + +32. String sql = "select \* from user where id = 100"; + +33. // 5、执行数据库操作 + +34. rs = stmt.executeQuery(sql); + +35. // 6、获取并操作结果集 + +36. **while** (rs.next()) { + +37. System.out.println(rs.getInt("id")); + +38. System.out.println(rs.getString("name")); + +39. } + +40. } **catch** (Exception e) { + +41. e.printStackTrace(); + +42. } **finally** { + +43. // 7、关闭对象,回收数据库资源 + +44. **if** (rs != **null**) { //关闭结果集对象 + +45. **try** { + +46. rs.close(); + +47. } **catch** (SQLException e) { + +48. e.printStackTrace(); + +49. } + +50. } + +51. **if** (stmt != **null**) { // 关闭数据库操作对象 + +52. **try** { + +53. stmt.close(); + +54. } **catch** (SQLException e) { + +55. e.printStackTrace(); + +56. } + +57. } + +58. **if** (conn != **null**) { // 关闭数据库连接对象 + +59. **try** { + +60. **if** (!conn.isClosed()) { + +61. conn.close(); + +62. } + +63. } **catch** (SQLException e) { + +64. e.printStackTrace(); + +65. } + +66. } + +67. } + +68. } + +69. } diff --git a/Java/JavaEE企业级开发/media/033dc67bcd465edb89b52cc8d9bdd5c1.png b/Java/JavaEE企业级开发/media/033dc67bcd465edb89b52cc8d9bdd5c1.png new file mode 100644 index 00000000..42f91680 Binary files /dev/null and b/Java/JavaEE企业级开发/media/033dc67bcd465edb89b52cc8d9bdd5c1.png differ diff --git a/Java/JavaEE企业级开发/media/0df06acb323561f7014fed6f60125206.jpeg b/Java/JavaEE企业级开发/media/0df06acb323561f7014fed6f60125206.jpeg new file mode 100644 index 00000000..a3e2f98a Binary files /dev/null and b/Java/JavaEE企业级开发/media/0df06acb323561f7014fed6f60125206.jpeg differ diff --git a/Java/JavaEE企业级开发/media/4f52e7856884d1457ab7d1867caab247.jpeg b/Java/JavaEE企业级开发/media/4f52e7856884d1457ab7d1867caab247.jpeg new file mode 100644 index 00000000..00a8bb49 Binary files /dev/null and b/Java/JavaEE企业级开发/media/4f52e7856884d1457ab7d1867caab247.jpeg differ diff --git a/Java/JavaEE企业级开发/media/896ddc649ace2c4d5b318d11c887ece9.jpeg b/Java/JavaEE企业级开发/media/896ddc649ace2c4d5b318d11c887ece9.jpeg new file mode 100644 index 00000000..78463e3f Binary files /dev/null and b/Java/JavaEE企业级开发/media/896ddc649ace2c4d5b318d11c887ece9.jpeg differ diff --git a/Java/JavaEE企业级开发/关于JAVAEE非框架的理解.md b/Java/JavaEE企业级开发/关于JAVAEE非框架的理解.md new file mode 100644 index 00000000..9a6a6119 --- /dev/null +++ b/Java/JavaEE企业级开发/关于JAVAEE非框架的理解.md @@ -0,0 +1 @@ +不能用过度的MVC框架的知识来理解简单的jsp页面,怎么说,现在写的jsp的级别就是将这些内容组合起来,一个页面与另一个页面杂糅式的交互。起始php与python这种直接接触框架的学习,反而非常不好。有时间多做东西救火啊,提高效率。才能有更多的理解。 diff --git a/Java/JavaEE企业级开发/关键字——transient.md b/Java/JavaEE企业级开发/关键字——transient.md new file mode 100644 index 00000000..21bd7805 --- /dev/null +++ b/Java/JavaEE企业级开发/关键字——transient.md @@ -0,0 +1,55 @@ +# 序列化 + +对序列化的理解 + +JAVA序列化是指把JAVA对象转换为字节序列的过程。JAVA反序列化是吧字节恢复为JAVA对象。 + +应用:当两个进程进行远程通信时,可以相互发送各种类型的数据。包括文本、图片、音频、视频,这些数据都是以二进制序列的形式在网络上传送。 + +两个JAVA进程通信的时候,也可以传送对象,将JAVA序列化为字节序列,装载为字节流,然后进行传送。.接收端将字节流反序列化为JAVA对象。 + +作用:实现了数据的持久化,通过序列化,能够将数据永久的保存到硬盘上。利用序列化可以实现数据流的输入输出和远程通信。 + +实现方法: + +java.io.ObjectOuptutStream:对象输出流writeObject() + +java.io.ObjectInputStream:对象输入流readObject() + +对象能被序列化的要求 + +implement了Serializable接口,通过默认的方法进行序列化 + +implement了Serializable接口,并且实现了相应的方法,然后通过自己的方式进行序列化和反序列化 + +序列化的步骤: + +步骤一:创建一个对象输出流,它可以包装一个其它类型的目标输出流,如文件输出流: + +ObjectOutputStream out = new ObjectOutputStream(new +fileOutputStream(“D:\\\\objectfile.obj”)); + +步骤二:通过对象输出流的writeObject()方法写对象: + +out.writeObject(“Hello”); + +out.writeObject(new Date()); + +反序列化的步骤: + +步骤一:创建一个对象输入流,它可以包装一个其它类型输入流,如文件输入流: + +ObjectInputStream in = new ObjectInputStream(new +fileInputStream(“D:\\\\objectfile.obj”)); + +步骤二:通过对象输出流的readObject()方法读取对象: + +String obj1 = (String)in.readObject(); + +Date obj2 = (Date)in.readObject(); + +# transient关键字说明 + +可以理解为瞬态、不可序列化。 + +简单的说,truansient 变量就是在对象序列化的过程中没有被序列化变量。 diff --git a/Java/JavaEE企业级开发/移动自动测试工具appium.md b/Java/JavaEE企业级开发/移动自动测试工具appium.md new file mode 100644 index 00000000..3494a0de --- /dev/null +++ b/Java/JavaEE企业级开发/移动自动测试工具appium.md @@ -0,0 +1,27 @@ +![968033-20160622111445922-1688525852.png](media/033dc67bcd465edb89b52cc8d9bdd5c1.png) + +使用appium的原理及过程说明: + +运行测试脚本的电脑,我们称为Client。 + +打开Appium,就开启了Appium Server,默认监听4723端口。 + +Appium +Server接收到Client命令(测试脚本),翻译成测试机器可以理解的语言,然后发送给测试机器运行。 + +测试机器运行结束后,再把测试结果返回给Appium Server,之后Appium +Server再把测试结果返回给Client。 + +![appium.jpg](media/4f52e7856884d1457ab7d1867caab247.jpeg) + +1.appium是c/s模式的 + +2.appium是基于webdriver协议添加对移动设备自动化api扩展而成的,所以具有和webdriver一样的特性,比如多语言支持 + +3.webdriver是基于http协议的,第一连接会建立一个session会话,并通过post发送一个json告知服务端相关测试信息 + +4.对于android来说,4.2以后是基于uiautomator框架实现查找注入事件的,4.2以前则是instrumentation框架的,并封装成一个叫Selendroid这玩意提供服务 + +5.客户端只需要发送http请求实现通讯,意味着客户端就是多语言支持的 + +6.appium服务端是node.js写的,所以你安装的时候无论哪个平台都是先装node diff --git a/Java/JavaEE企业级开发/简单的实验.md b/Java/JavaEE企业级开发/简单的实验.md new file mode 100644 index 00000000..cd178326 --- /dev/null +++ b/Java/JavaEE企业级开发/简单的实验.md @@ -0,0 +1,96 @@ +WEB-INF web.xml + +文件用来配置整个工程。 + +\ + +\ + +\FirstServlet\ + +\lesson.j2ee.ex1.FirstServlet\ + +\ + +\ + +\FirstServlet\ + +\/Serv1\ + +\ + +\ + +(也许讲过,但是感觉从来没有学过怎么开发,知识知道Javaservlet的一些基础理论知识,真的需要学习一下这方面的东西了。如何真正的使用Java开发一个工程。) + +Servlet通过回调函数管理自己的生命周期 + +init()-\>初始化 + +sevice()-\>提供servlet服务。 + +\-doGet()用于相应GET方法的函数,HTTPSevlet类中实现 + +\-doPost()用于响应POST方法的函数,HTTPSevlet类中实现 + +\-doHead()用于响应HEAD方法的函数,HTTPSevlet类中实现。 + +destroy()-\>销毁 + +getServletConfig()用来获取Servlet配置信息。 + +getSeviceInfo()用来获取其他信息。 + +关于Servlet的继承关系,必须知道每一级继承都实现了什么玩意。 + +Servlet \<-- GenericServlet \<-- HttpServlet \<--- MyServlet + +关于servlet中常用到的两个对象 + +ServletConfig对象 + +每个servlet都有一个ServletConfig对象;用于向servlet传递部署时的信息;用于访问ServletContext;其参数在DD中配置 + +ServletContext对象 + +每个web应用都有一个ServletContext;用于访问web应用的参数(在DD中配置);用于获取服务器信息;存放其它公用信息 + +请求与响应 + +ServletRequest \<--- HTTPServletRequest \<--- realRequest + +SerbletResponse \<---- HTTPSerbletResponse \<---realResponse + +java +与你写的python还是有很多不同的,面向对象思想比较深刻。所以,每次设计到一个内容,首先了解有哪些类-对象, +每个类-对象由哪些属性 , 每个类-对象有那些方法; +因为每个类的功能和作用比较固定,所以属性和方法一般是与此功能相关的,笔记哦啊容易记忆。 + +已经涉及到的对象 + +HttpServlet -对象,每次请求会实例化。 + +Request -对象 + +Response -对象 + +ServletConfig - 对象 + +SerletContext - 对象 + +还是第一次真正的用到cookie,那么思考一下如何使用cookie。 + +用户携带cookie值(如果有的话)请求一个网页。 + +服务器端读取cookie值,如果存在cookie值,则添加到页面当中。 + +当前用的这个东西存在一定的弊端。直接通过cookie获取当前用户的身份。 diff --git a/Java/JavaEE企业级开发/软件测试中的总结.md b/Java/JavaEE企业级开发/软件测试中的总结.md new file mode 100644 index 00000000..6357c652 --- /dev/null +++ b/Java/JavaEE企业级开发/软件测试中的总结.md @@ -0,0 +1,27 @@ +感觉配置环境的过程中,对这些东西一知半解。 + +1\. 首先安装eclipse,jdk/jre,adt插件,完成eclipse开发Android环境的基础设备。 + +2. +安装了node.js并配置了相关的环境,使得系统能够编译并运行node.js的代码。然而跟我们的工程有什么联系,一点都不知道。 + +:经过了解得知,安装node的原因是因为,node的服务器端,是由node.js写的,也就是说,node并不是用来进行编译客户端的代码的,而是用来运行appium的服务器端程序的。 + +3. +安装Appium软件(这玩意不是系统插件),是一个调试的监视工具吧。具体怎么运作也不知道。 + +:经过了解得知,这个东西封装了对各种移动设备框架的调试方法,通过服务器端,连接客户端和移动设备。客户端通过url的形式访问服务器端,完成对移动设备的调试。 + +4\. APPium调试过程依赖的jar包包括测试类库: + +Selenum类库(selenium.jar) + +Appium类库(client.jar)不知道是干啥用的 + +5\. 关联了相关的文件(apk appt appt.exe)不知道是干啥用的 + +6\. 启动了Android模拟器,或者连接了真机。 + +7\. 启动Appium工具,并通过junit的方式对软件进行调试。 + +总之,今天最大的收获,可能就是对eclipse自动构建java工程结构有了更多的了解。 diff --git a/Java/Java基础/JAVA数据近似.md b/Java/Java基础/JAVA数据近似.md new file mode 100644 index 00000000..3210c1d5 --- /dev/null +++ b/Java/Java基础/JAVA数据近似.md @@ -0,0 +1,30 @@ +下面来介绍将小数值舍入为整数的几个方法:Math.ceil()、Math.floor()和Math.round()。 +这三个方法分别遵循下列舍入规则: + +Math.ceil()执行向上舍入,即它总是将数值向上舍入为最接近的整数; + +Math.floor()执行向下舍入,即它总是将数值向下舍入为最接近的整数; + +Math.round()执行标准舍入,即它总是将数值四舍五入为最接近的整数(这也是我们在数学课上学到的舍入规则)。 + +下面来看几个例子: + +Math.ceil(25.9) //26 + +Math.ceil(25.5) //26 + +Math.ceil(25.1) //26 + +Math.ceil(25.0) //25 + +Math.round(25.9) //26 + +Math.round(25.5) //26 + +Math.round(25.1) //25 + +Math.floor(25.9) //25 + +Math.floor(25.5) //25 + +Math.floor(25.1) //25 diff --git a/Java/Java基础/事件监听机制.md b/Java/Java基础/事件监听机制.md new file mode 100644 index 00000000..d75ab3c9 --- /dev/null +++ b/Java/Java基础/事件监听机制.md @@ -0,0 +1,117 @@ +## 新的事件监听机制 + +----- + +* 之前是定义一个组件对象(事件源),队组建对象绑定一个监听器对象,在监听器对象中有监听同一事件不同动作的函数,函数内部对事件进行处理。从监听器的角度对事件和动作进行处理。 +* 现在是直接将静态事件绑定到事件源上,通过process函数运行运行事件发生时的处理方式。而且这些静态事件是已经存在于awtEvent类中的。 + +``` + + package EventHandle; + + import java.awt.*; + import java.awt.event.ComponentEvent; + import java.awt.event.MouseEvent; + import java.awt.event.WindowEvent; + + /** + * @author 宙斯 + * 准确的说这并不是先前的事件监听机制吧。它不存在指明的监听器。 + * 应该更像一种组件自带的事件匹配功能。 + * 具体步骤: + * 打开某一类型的事件匹配功能。 + * 使用process函数运行某个事件 + * 当事件发生时通过事件的ID匹配具体的动作。 + * 匹配后设置相应的处理方式。 + */ + + public class baseEvent extends Frame{ + private int x = 0,y = 0,flag = 0; + private Image img; + private int dx = 0,dy = 0; + + public static void main(String[] args) { + baseEvent bE = new baseEvent(); + } + public baseEvent(){ + super(); + setSize(500,500); + this.setVisible(true); + + Toolkit tk = Toolkit.getDefaultToolkit(); + img = tk.getImage("first.png"); + + //相当于添加了对Component事件的监听器,似乎监听器类在底层已经直接绑定。 + enableEvents(AWTEvent.COMPONENT_EVENT_MASK); + enableEvents(AWTEvent.WINDOW_EVENT_MASK); + enableEvents(AWTEvent.MOUSE_EVENT_MASK); + + repaint(); + + } + + //直接调用底层的事件处理函数 + public void processComponentEvent(ComponentEvent e){ + if(e.getID() == ComponentEvent.COMPONENT_MOVED){ + System.out.println(e.getSource()); + System.out.println(e.getID()); + + } + } + + public void processWindowEvent(WindowEvent e){ + if(e.getID() == WindowEvent.WINDOW_CLOSING){ + System.exit(0); + } + } + /* + public void processMouseEvent(MouseEvent e){ + if(e.getID() == MouseEvent.MOUSE_PRESSED){ + System.out.println("pressed"); + if((e.getX()>= x)&&(e.getX()<=x+100)&&(e.getY()>=y)&&(e.getY()<=y+100)){ + flag = 1; + System.out.println(e.getX()+"..."+e.getY()); + + } + } + if((e.getID()==MouseEvent.MOUSE_RELEASED)&&(flag == 1)){ + x = e.getX(); + y = e.getY(); + repaint(); + flag = 0; + } + } + */ + public void processMouseEvent(MouseEvent e){ + if(e.getID() == MouseEvent.MOUSE_PRESSED){ + System.out.println("pressed"); + if((e.getX()>= x)&&(e.getX()<=x+100)&&(e.getY()>=y)&&(e.getY()<=y+100)){ + dx = e.getX()-x; + dy = e.getY()-y; + flag = 1; + System.out.println(e.getX()+"..."+e.getY()); + + } + } + if(e.getID()== MouseEvent.MOUSE_MOVED&&flag ==1){ + x = e.getX()-dx; + y = e.getY()-dy; + System.out.println(e.getX()+"..."+e.getY()); + + repaint(); + + } + if((e.getID()==MouseEvent.MOUSE_RELEASED)&&(flag == 1)){ + flag = 0; + } + + } + public void paint(Graphics g){ + g.drawImage(img, x, y,100,100, this); + } + + +} + + +``` \ No newline at end of file diff --git a/Java/Java基础/多线程共享受限资源.md b/Java/Java基础/多线程共享受限资源.md new file mode 100644 index 00000000..121799fd --- /dev/null +++ b/Java/Java基础/多线程共享受限资源.md @@ -0,0 +1,14 @@ +# 多线程共享受限资源 + +---- + +## >多线程共享受限资源存在的问题 + + +---- + +* **这个描述???** + 当你坐在桌子旁边时,手里有有一把叉子,准备插起盘子里最后一块十五,当叉子碰到十五的时候,它忽然消失了。 + +* **解决方法** + 给这个资源加锁,每个线程访问这个资源时上锁,访问结束后开锁。 \ No newline at end of file diff --git a/Java/Java基础/多线程理论补充.md b/Java/Java基础/多线程理论补充.md new file mode 100644 index 00000000..a0eeb23b --- /dev/null +++ b/Java/Java基础/多线程理论补充.md @@ -0,0 +1,48 @@ +# 多线程理论补充 + +------ + +## >让步机制 + +----- + +* **yield()** + thread.yield()线程执行这个函数会主动放弃执行的优先级,但只是暗示别的线程能够抢到更多的资源,没有确定的机制保证cpu资源一定被其他线程使用。 + +## >休眠机制 + +--- + +* **sleep()** + thread.sleep(30)线程停止执行30ms,可能会跑出异常,此线程调用interrupt()方法,中断了线程的执行。 + +## >优先权机制 + +---- + +* **setPriority()** + thread.setPriority()通过thread类中的常量对优先级进行设定。thread.getPriority()能够获取当前线程的优先级。 + +## >后台进程 + +----- + +* **后台线程(守护线程)thread.setDaemon()** + 程序运行时,在后台提供的一种通用的线程,当所有的非后台线程结束时,后台线程(守护线程)自动终止。必须在线程启动之前,调用方法setDaemon(),将线程设置成后台线程。isDeamon()判断是否为后台线程。 + +## >加入线程 + +---- + +* **t.join(a)** + t线程此时将被挂起,直到a线程结束才会被执行。当a线程结束时,t.isAlive()返回为假,线程恢复。 + +## >编码变体 + +----- + +* **implements Runnable** + 通过实现接口Runnable来达到作为线程类的方法。必须实现run方法。 + +* **建立有响应的用户界面** + 让运算作为一个独立的线程在后台独立运行。 diff --git a/Java/Java基础/多线程的应用.md b/Java/Java基础/多线程的应用.md new file mode 100644 index 00000000..5fa17930 --- /dev/null +++ b/Java/Java基础/多线程的应用.md @@ -0,0 +1,40 @@ +# 多线程的应用 + +------ + +## 多线程停止线程 + +---- + +* stop方法已经过时不能使用,只能当run方法结束时,才能终止线程。开启多线程程运行时,代码通常是循环结构,只要控制住线程,通常可以让run方法结束。 +* 应当设计可以修改的无限循环标志。跳出无限循环,则会终止线程。 +* 当线程在循环内进入等待状态时,及时线程的循环条件不满足,必须终止线程,但是无法执行到判断语句进行线程的终止,此时,必须使用interrupt()函数来达到要求。 +* interrupt将处于冻结状态的线程强制转换到运行状态。此时wait()就会跑出我们处理已久的中断异常。 +* 当没有指定的方式让冻结的线程回复到运行状态时,这是需要对冻结进行清除。Thread提供了interrupt方法。 + + +## 多线程 守护线程 + +----- + +* 守护线程就是后台线程,也是一种依赖线程 +* 特点: + 当前台线程结束后,后台线程会自动终止,作为依赖线程,守护线程,不用强调结束。 +* 方法: + setDemon()设置某个线程为守护线程 + +## 多线程join方法 + +---- + +* t1.join() t1抢夺cpu执行权,主线程处于冻结状态,t1优先执行。相当于顺序执行两个线程。主线程碰到谁的join就会等谁执行。 +* 当A线程执行到了B线程的Join方法时,A线程就会等待,等B线程都执行完成,A才会执行。join才会临时加入线程执行。当B线程进入wait时,A线程也能继续执行。 +* toString 方法能够显示线程的名称,线程的优先级,线程当前的分组(线程组谁调用就是谁的线程组的) +* 所有线程包括主线程,默认是5。数越大优先级越高。MAX_PRIORITY,MIN_PRIORITY, +* yield()方法,当线程读到这里是,会释放执行权。这样会使所有的线程都有平均执行的效果。 + +## 什么时候会使用到多线程 + +---- + +* 当程序独立运算相互之间不相关的时候,可以用多线程封装一下,提高程序执行的速度 \ No newline at end of file diff --git a/Java/Java基础/多线程间的通讯.md b/Java/Java基础/多线程间的通讯.md new file mode 100644 index 00000000..bf7807e6 --- /dev/null +++ b/Java/Java基础/多线程间的通讯.md @@ -0,0 +1,166 @@ +# 多线程间的通讯 + +----- + +## 多线程通讯的定义: + +---- + +- 多个不同的线程对共同的数据进行不同的操作。 + +## 多线程通讯间的安全问题 + +----- + +* 安全问题的原因 + 例如当多个线程对同一个数据进行不同操作时,导致各种操作的先后顺序出现混乱。 +* 安全问题的解决方式 + 对这些线程操作数据的部分进行同步处理,使用相同的锁,将不同的部分锁起。 + +## 线程间通讯等待唤醒机制 + +----- + +* 可以模仿锁的工作原理(设置标志位,记录当前是够线程占用锁内的程序,实现只能有一个线程执行锁内代码的现象) +* 步骤: + 1. 设置标志位flag + 2. 当标志位处于输入状态时,执行输入程序,执行完成后修改为输出状态。 + 3. 当标志位处于输出状态时,执行输出程序,执行完成后修改为输入状态。 +## 等待唤醒机制的具体实现 + +---- + +* wait()和notify()函数必须在同步代码块或者同步函数当中使用。注意wait()会抛出中断异常。对持有监视器(锁)的线程进行操作。 +* wait()和notify()的操作对象是同步中持有当前锁的线程。 +* 线程的等待唤醒机制必须制定一把确定的锁。锁是任意的对象,任意对象都能成为锁,成为锁之后都能调用wait和notify的方法。而且这些方法都定义在Object类中。只有同一个锁上的被等待线程可以被同一个notify唤醒。等待唤醒必须是同一个锁。 + +## 使用新的工具类实现程序锁定和解锁 + +---- + + package painting; + + import java.util.concurrent.locks.Condition; + import java.util.concurrent.locks.Lock; + import java.util.concurrent.locks.ReentrantLock; + + /** + * @author 宙斯 + * + */ + public class LockerUsing { + + /** + * @param args + */ + public static void main(String[] args) { + Resource2 r = new Resource2(); + Produce2 pro = new Produce2(r); + Consumer2 con = new Consumer2(r); + + Thread t1 = new Thread(pro); + Thread t2 = new Thread(con); + Thread t3 = new Thread(pro); + Thread t4 = new Thread(con); + t1.start(); + t2.start(); + t3.start(); + t4.start(); + } + + } + class Resource2{ + private String name; + private int count =1; + private boolean flag = false; + private Lock lock = new ReentrantLock();//新建了一个锁对象 + private Condition condition_con = lock.newCondition();//生成了一个与锁相关的控制对象 + private Condition condition_pro = lock.newCondition(); + public void set(String name) throws InterruptedException{ + lock.lock(); + try{ + while(flag) + condition_pro.await(); + + this.name= name+"..."+count++; + System.out.println(Thread.currentThread().getName()+"生产者:"+this.name); + flag = true; + condition_con.signal(); + } + finally{ + lock.unlock();//异常处理当中释放锁的动过一定要被执行 + + } + } + public void out() throws InterruptedException{ + lock.lock(); + try{ + while(!flag) + condition_con.await(); + System.out.println(Thread.currentThread().getName()+"消费者:"+this.name); + flag = false; + condition_pro.signalAll(); + } + finally{ + lock.unlock(); + } + } + } + class Produce2 implements Runnable{ + private Resource2 res; + Produce2(Resource2 res){ + this.res = res; + + } + public void run() + { + while(true){ + try { + res.set("商品"); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + + class Consumer2 implements Runnable{ + private Resource2 res; + Consumer2(Resource2 res){ + this.res = res; + + } + public void run() + { + while(true){ + try { + res.out(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + + +* 代码的解释: + + 1. 单线程 -----多线程-----多线程操作同一个数据源的时候实行同步机制------带有满足条件的同步机制(睡眠唤醒机制) + 2. 实现了多线程不同操作相同的程序,这个类具有模板的价值.对资源的不同操作写到资源类中,并使用this资源类的锁,对各种不同的操作进行上锁 + 3. 而非写到其他操作类中,这样能够将同步和冲突解决都封装到资源类中便于理解和操作。 + 4. 当线程数多于两个,比如此程序中有两个在生产两个在消费,那么标准的方式应该是通过循环判断标志位是否合格, + 因为当某个线程判断满足后,但在进入之前肯能被其他线程修改标志位。 + 而且必须使用notifyAll()唤醒所有的线程。 + 5. 使用Locker及其相关类的好处 + 一个Locker上可以有很多condition对象执行操作,也就是只唤醒对方的condition + jdk1.5实现了多线程的升级解决方案 + 将同步设置Synchronize替换成Lock操作,可见 + 将Object中wait,notify,notifyAll替换成Condition对象。该对象可以Locker锁进行获取 + + + + + + diff --git a/Java/Java基础/底层事件处理.md b/Java/Java基础/底层事件处理.md new file mode 100644 index 00000000..3422200c --- /dev/null +++ b/Java/Java基础/底层事件处理.md @@ -0,0 +1,5 @@ +# 底层事件处理 + +----- + +* 在java.awt学习的时候,将监听器绑定到事件源上,当指定事件发生时监听器会自动匹配到相应的动作,执行相应的处理方式。但在底层事件处理过程中,不许要监听器,能够直接获取当前发生的底层事件,然后进行匹配处理。 \ No newline at end of file diff --git a/Java/Java网络编程/RMI相关知识.md b/Java/Java网络编程/RMI相关知识.md new file mode 100644 index 00000000..6cca5484 --- /dev/null +++ b/Java/Java网络编程/RMI相关知识.md @@ -0,0 +1,159 @@ +RMI的定义 + +RPC (Remote Procedure +Call):远程方法调用,用于一个进程调用另一个进程中的过程,从而提供了过程的分布能力。 + +RMI(Remote Method +Invocation):远程方法调用,即在RPC的基础上有向前迈进了一步,提供分布式对象间的通讯。允许运行在一个java +虚拟机的对象调用运行在另一个java虚拟机上对象的方法。这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中。 + +RMI的作用 + +RMI的全称宗旨就是尽量简化远程接口对象的调用。 + +RMI大大增强了java开发分布式应用的能力,例如可以将计算方法复杂的程序放在其他的服务器上,主服务器只需要去调用,而真正的运算是在其他服务器上进行,最后将运算结果返回给主服务器,这样就减轻了主服务器的负担,提高了效率(但是也有其他的开销)。 + +RMI网络模型 + +在设计初始阶段,我们真正想要的是这样一种机制,客户端程序员以常规方式进行方法调用,而无需操心将数据发送到网络上或者解析响应之类的问题。所以才有了如下的网络模型:在客户端为远程对象安装一个代理。代理是位于客户端虚拟机中的一个对象,它对于客户端程序来说,就像是要访问的远程对象一样。客户端调用此代理时,只需进行常规的方法调用。而客户端代理则负责使用网络协议与服务器进行联系。 + +![8-343985609.jpeg](media/b24ac0390788e8547c3f60daee9eaacf.jpeg) + +现在的问题在于代理之间是如何进行通信的?通常有三种方法: + +1、CORBA:通过对象请求代理架构,支持任何编程语言编写的对象之间的方法调用。 + +2、SOAP + +3、RMI:JAVA的远程方法调用技术,支持java的分布式对象之间的方法调用。 + +其中CORBA与SOAP都是完全独立于言语的,可以使用C、C++、JAVA来编写,而RMI只适用于JAVA。 + +RMI的工作原理 + +**术语介绍** + +> 1、存根:当客户端要调用远程对象的一个方法时,实际上调用的是代理对象上的一个普通方法,**我们称此代理对象为存根(stub)。**存根位于客户端机器上,而非服务器上。 + +> 2、参数编组:存根会将**远程方法所需的参数打包成一组字节**,对参数编码的过程就称为参数编组。参数编组的目的是将参数转换成适合在虚拟机之间进行传递的格式,在RMI协议中,对象是使用序列化机制进行编码的。 + +编程模型 + +为了介绍RMI的编程模型,我下面会编写一个DEMO。远程对象表示的是一个仓库,而客户端程序向仓库询问某个产品的价格。 + +**接口定义** + +远程对象的能力是由在客户端和服务器之间共享的接口所表示的: + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +package rmi; import java.rmi.Remote; import java.rmi.RemoteException; public +interface Warehouse extends Remote { double getPrice(String description) throws +RemoteException; } + +远程对象的接口必须扩展Remote接口,它位于java.rmi包中。接口中所有的方法必须声明抛出RemoteException异常。这是因为远程方法总是存在失败的可能,所以java编程语言要求每一次远程方法的调用都必须捕获RemoteException,并且指明当调用不成功时应执行的相应处理操作。 + +**接口的实现** + +![copycode.gif](media/51e409b11aa51c150090697429a953ed.gif) + +复制代码 + +package rmi; import java.rmi.RemoteException; import +java.rmi.server.UnicastRemoteObject; import java.util.HashMap; import +java.util.Map; public class WarehouseImpl extends UnicastRemoteObject implements +Warehouse { private static final long serialVersionUID = 1L; private +Map\ prices; protected WarehouseImpl() throws RemoteException { +prices = new HashMap\(); prices.put("mate7",3700.00); } public +double getPrice(String description) throws RemoteException { Double price = +prices.get(description); return price == null? 0 : price; }} + +你可以看出这个类是远程方法调用的目标,因为它扩展自UnicastRemoteObject,这个类的构造器使得它的对象可供远程访问。 + +**RMI注册表:通过JNDI发布RMI服务** + +1、要访问服务器上的一个远程对象时,客户端必须先得到一个本地的存根对象,也就是客户端机器上的代理对象。那么问题来了,如何才能得到这个存根呢? + +2、为此,JDK提供了自举注册服务(bootstrap registry +service),服务器程序应该使用自举注册服务来注册至少一个远程对象。 + +3、而要注册一个远程对象,需要一个RMI URL和一个对实现对象的引用。 + +4、RMI +的URL以rmi:开头,后接域名或IP地址(host),紧接着是端口号(port),最后是服务名(service)。 + +如:rmi://regserver.mycompany.cmo:99/central_warehouse + +如果我们是在本地发布RMI服务,那么host就是“localhost”,此外RMI默认的端口号是“1099”,当然我们也可以自行设置,只要不与其他端口重复即可。service实际上是基于同一个host与port下唯一的服务名。 + +发布RMI服务: + +1 package rmi; 2 3 import java.net.MalformedURLException; 4 import +java.rmi.AlreadyBoundException; 5 import java.rmi.Naming; 6 import +java.rmi.RemoteException; 7 import java.rmi.registry.LocateRegistry; 8 9 import +javax.naming.NamingException; 10 11 12 public class WarehouseServer 13 { 14 +public static void main(String[] args) throws RemoteException, NamingException, +MalformedURLException, AlreadyBoundException 15 { 16 +System.out.println("Constructing server implementation"); 17 WarehouseImpl +centralWarehouse = new WarehouseImpl(); 18 19 System.out.println("Binding server +implementation to registry"); 20 LocateRegistry.createRegistry(1099); 21 +Naming.bind("rmi://localhost:1099/central_warehoues",centralWarehouse); 22 23 +System.out.println("Waiting for invocations from clients ..."); 24 } 25 } + +运行结果: + +Constructing server implementation Binding server implementation to registry +Waiting for invocations from clients ... + +1、第20行只需提供一个port,就在JNDI中创建了一个注册表。 + +2、第21行通过bind方法绑定了RMI地址与RMI服务实现类。 + +3、执行这个方法后,相当于自动发布了RMI服务。接下来要做的事情就是写一个RM客户端调用已发布的RMI服务。 + +**客户端调用RMI服务** + +1 package rmi; 2 3 import java.net.MalformedURLException; 4 import +java.rmi.Naming; 5 import java.rmi.NotBoundException; 6 import +java.rmi.RemoteException; 7 import javax.naming.NamingException; 8 9 public +class WarehouseClient 10 { 11 public static void main(String[] args) throws +NamingException, RemoteException, MalformedURLException, NotBoundException 12 { +13 System.out.println("RMI registry binding:"); 14 String url = +"rmi://localhost:1099/central_warehoues"; 15 Warehouse centralWarehouse = +(Warehouse) Naming.lookup(url); 16 String descr = "mate7"; 17 double price = +centralWarehouse.getPrice(descr); 18 System.out.println(descr + ":" + price); 19 +} 20 } + +运行结果: + +RMI registry binding: mate7:3700.0 + +补充说明: + +> 服务调用只需要知道两个东西:1、RMI请求路径;2、RMI接口名 + +> 第15行,这里用的是接口名Warehouse,而不是实现类。一定不能RMI接口的实现类,否则就是本地调用了。 + +> 查看运行结果,我们知道这次DEMO展示的远程调用成功了。 + +**下面我们来看下RMI的网络示意图:** + +![3-765464905.jpeg](media/f2f880588756d88cbf5083a94fbd41ae.jpeg) + +1、借助JNDI这个所谓的命名与目录服务,我们成功地发布并调用了RMI服务。实际上,JNDI就是一个注册表,服务端将服务对象放入到注册表中,客户端从注册表中获取服务对象。 + +2、在服务端我们发布了RMI服务,并在JNDI中进行了注册,此时就在服务端创建了一个Skeleton(骨架),当客户端第一次成功连接JNDI并获取远程服务对象后,立马在本地创建了一个Stub(存根)。 + +3、远程通信实际是通过Skeleton与Stub来完成的,数据是基于TCP/IP协议,在“传输层”上发送的。 + +4、毋庸置疑,理论上RMI一定比WebService要快,毕竟WebService是基于http协议的,而http所携带的数据是通过“应用层”来传输的。传输层较应用层更为底层,越底层越快。 + +RMI的局限性 + +1、只能实现JAVA系统之间的调用,而WebService可以实现跨语言实现系统之间的调用。 + +2、RMI使用了JAVA默认的序列化方式,对于性能要求比较高的系统,可能需要其他的序列化方案来解决。 + +3、RMI服务在运行时难免会存在故障,例如,如果RMI服务无法连接了,就会导致客户端无法响应的现象。 diff --git a/Java/Java网络编程/StringBuffer.md b/Java/Java网络编程/StringBuffer.md new file mode 100644 index 00000000..3b3f69c7 --- /dev/null +++ b/Java/Java网络编程/StringBuffer.md @@ -0,0 +1,140 @@ +String与StringBuffer的区别 + +简单地说,就是一个变量和常量的关系。StringBuffer对象的内容可以修改;而String对象一旦产生后就不可以被修改,重新赋值其实是两个对象。 + +StringBuffer的内部实现方式和String不同,StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类。所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入、删除等操作,使用StringBuffer要更加适合一些。 + +String:在String类中没有用来改变已有字符串中的某个字符的方法,由于不能改变一个java字符串中的某个单独字符,所以在JDK文档中称String类的对象是不可改变的。然而,不可改变的字符串具有一个很大的优点:编译器可以把字符串设为共享的。 + +StringBuffer:StringBuffer类属于一种辅助类,可预先分配指定长度的内存块建立一个字符串缓冲区。这样使用StringBuffer类的append方法追加字符 +比 String使用 + 操作符添加字符 到 一个已经存在的字符串后面有效率得多。因为使用 + +操作符每一次将字符添加到一个字符串中去时,字符串对象都需要寻找一个新的内存空间来容纳更大的字符串,这无凝是一个非常消耗时间的操作。添加多个字符也就意味着要一次又一次的对字符串重新分配内存。使用StringBuffer类就避免了这个问题。 + +StringBuffer是线程安全的,在多线程程序中也可以很方便的进行使用,但是程序的执行效率相对来说就要稍微慢一些。 + +StringBuffer的常用方法 + +StringBuffer类中的方法要偏重于对字符串的变化例如追加、插入和删除等,这个也是StringBuffer和String类的主要区别。 + +1、append方法 + +public StringBuffer append(boolean b) + +该方法的作用是追加内容到当前StringBuffer对象的末尾,类似于字符串的连接。调用该方法以后,StringBuffer对象的内容也发生改变,例如: + +StringBuffer sb = new StringBuffer(“abc”); + +sb.append(true); + +则对象sb的值将变成”abctrue”。 + +使用该方法进行字符串的连接,将比String更加节约内容,例如应用于数据库SQL语句的连接,例如: + +StringBuffer sb = new StringBuffer(); + +String user = “test”; + +String pwd = “123”; + +sb.append(“select \* from userInfo where username=“) + +.append(user) + +.append(“ and pwd=”) + +.append(pwd); + +这样对象sb的值就是字符串“select \* from userInfo where username=test and +pwd=123”。 + +2、deleteCharAt方法 + +public StringBuffer deleteCharAt(int index) + +该方法的作用是删除指定位置的字符,然后将剩余的内容形成新的字符串。例如: + +StringBuffer sb = new StringBuffer(“Test”); + +sb. deleteCharAt(1); + +该代码的作用删除字符串对象sb中索引值为1的字符,也就是删除第二个字符,剩余的内容组成一个新的字符串。所以对象sb的值变为”Tst”。 + +还存在一个功能类似的delete方法: + +public StringBuffer delete(int start,int end) + +该方法的作用是删除指定区间以内的所有字符,包含start,不包含end索引值的区间。例如: + +StringBuffer sb = new StringBuffer(“TestString”); + +sb. delete (1,4); + +该代码的作用是删除索引值1(包括)到索引值4(不包括)之间的所有字符,剩余的字符形成新的字符串。则对象sb的值是”TString”。 + +3、insert方法 + +public StringBuffer insert(int offset, String s) + +该方法的作用是在StringBuffer对象中插入内容,然后形成新的字符串。例如: + +StringBuffer sb = new StringBuffer(“TestString”); + +sb.insert(4,“false”); + +该示例代码的作用是在对象sb的索引值4的位置插入字符串false,形成新的字符串,则执行以后对象sb的值是”TestfalseString”。 + +4、reverse方法 + +public StringBuffer reverse() + +该方法的作用是将StringBuffer对象中的内容反转,然后形成新的字符串。例如: + +StringBuffer sb = new StringBuffer(“abc”); + +sb.reverse(); + +经过反转以后,对象sb中的内容将变为”cba”。 + +5、setCharAt方法 + +public void setCharAt(int index, char ch) + +该方法的作用是修改对象中索引值为index位置的字符为新的字符ch。例如: + +StringBuffer sb = new StringBuffer(“abc”); + +sb.setCharAt(1,’D’); + +则对象sb的值将变成”aDc”。 + +6、trimToSize方法 + +public void trimToSize() + +该方法的作用是将StringBuffer对象的中存储空间缩小到和字符串长度一样的长度,减少空间的浪费。 + +7、构造方法: + +StringBuffer s0=new StringBuffer();分配了长16字节的字符缓冲区 + +StringBuffer s1=new StringBuffer(512);分配了512字节的字符缓冲区 + +8、获取字符串的长度: length() + +StringBuffer s = new StringBuffer("www"); + +int i=s.length(); + +m.返回字符串的一部分值 + +substring(int start) //返回从start下标开始以后的字符串 + +substring(int start,int end) //返回从start到 end-1字符串 + +9.替换字符串 + +replace(int start,int end,String str) + +s.replace(0,1,"qqq"); + +10.转换为不变字符串:toString()。 diff --git a/Java/Java网络编程/XML语言学习.md b/Java/Java网络编程/XML语言学习.md new file mode 100644 index 00000000..72c4a9e5 --- /dev/null +++ b/Java/Java网络编程/XML语言学习.md @@ -0,0 +1,189 @@ +简介 + +**作用:** + +用来传输和存储数据 + +**定义:** + +可扩展标记语言。 + +**特点:** + +自行定义标签,具有自我描述性。 + +能够跨越各种平台 + +**具体应用:** + +用于描述可用的web服务的WSDL + +树结构 + +**范例** + +\\\Tove\\Jani\\Reminder\\Don't +forget me this weekend!\\ + +说明:第一行是XML文档声明,定义了版本号和文档的编码方式。 + +**树结构:** + +![clipboard.png](media/ab38369f8043d690b448fe8e8004a755.png) + +**元素:** + +起始标记、结束标记、内容(可以是字符文本、其他元素、混合物) + +**属性:** + +属性名=属性值 + +**语法规则:** + +标签闭合,正确嵌套 + +有一个根元素 + +可以有树枝也可以由实体引用 + +XML声明可选,放在第一行 + +XML标签对大小写敏感 + +属性值必须加引号,应当尽量用子元素代替属性。数据的数据存储为属性,而数据本身应当存储为元素。 + +id属性可以用来标识XML元素 + +注释方式\