public class Wine{
public void fun1(){
System.out.println("Wine 的Fun.....");
fun2();
}
public void fun2(){
System.out.prinltn("Wine 的Fun2");
}
}
public class JNC extends Wine{
/**
* @desc 子类重载父类方法
* 父类中不存在该方法,向上转型后,父类是不能引用该方法的
* @param a
* @return void
*/
public void fun1(String a){
System.out.println("JNC 的 Fun1...");
fun2();
}
/**
* 子类重写父类方法
* 指向子类的父类引用调用fun2时,必定是调用该方法
*/
public void fun2(){
System.out.println("JNC 的Fun2...");
}
}
public class Test {
public static void main(String[] args) {
Wine a = new JNC();
a.fun1();
}
}
public interface Testabs {
void fun();
void setType(boolean flag);
}
public abstract class Test implements Testabs {
@Override public void fun() {
System.out.println("Test fun....");
}
}
public class Wine extends Test{
@Override public void setType(boolean flag) {
}
public static void main(String[] args){
Testabs w = new Wine();
w.fun();
}
}
public class Test {
class Bean1 { //成员内部类
public int I = 0;
}
static class Bean2 {//静态内部类
public int J = 0;
}
public static void main(String[] args){
Test test = new Test();
Bean1 bean1 = test.new Bean1();
bean1.I++;
Bean2 bean2 = new Bean2();
bean2.J++;
Bean bean = new Test().new Bean();
Bean.Bean3 bean3 = bean.new Bean3();
bean3.K++;
}
class Bean {
class Bean3 {
public int K = 0;
}
}
}
public class Test {
public static void main(String[] args) {
Outter outter = new Outter();
outter.new Inner().print();
}
}
class Outter
{
private int a = 1;
class Inner {
private int a = 2;
public void print() {
int a = 3;
System.out.println("局部变量:" + a);
System.out.println("内部类变量:" + this.a);
System.out.println("外部类变量:" + Outter.this.a);
}
}
}
查找,替换操作 int binarySearch(List list, Object key), 对List进行二分查找,返回索引,注意List必须是有序的 int max(Collection coll),根据元素的自然顺序,返回最大的元素。 类比int min(Collection coll) int max(Collection coll, Comparator c),根据定制排序,返回最大元素,排序规则由Comparatator类控制。类比int min(Collection coll, Comparator c) void fill(List list, Object obj),用元素obj填充list中所有元素 int frequency(Collection c, Object o),统计元素出现次数 int indexOfSubList(List list, List target), 统计targe在list中第一次出现的索引,找不到则返回-1,类比int lastIndexOfSubList(List source, list target). boolean replaceAll(List list, Object oldVal, Object newVal), 用新元素替换旧元素。
public static void fun1(){
List list = new ArrayList<>();
list.add(12);
list.add(-15);
list.add(7);
list.add(4);
list.add(35);
list.add(9);
System.out.println("源列表:" + list);
System.out.println("最大的元素: " + Collections.max(list));
System.out.println("最小元素: " + Collections.min(list));
Collections.replaceAll(list,-15, 35);
System.out.println("用新元素替换旧元素: " + list);
System.out.println("统计元素出现次数: " + Collections.frequency(list, 35));
Collections.sort(list);
System.out.println("先sort排序,然后对List进行二分查找,得到的是索引: " + Collections.binarySearch(list, 35));
int index = Collections.binarySearch(list, 35, new Comparator() {
@Override public int compare(Integer int1, Integer int2) {
return int1.compareTo(int2);
}
});
System.out.println("先sort排序,然后对List进行二分查找,得到的是索引: " + index);
}
Collections同步控制 Collections中几乎对每个集合都定义了同步控制方法,例如 SynchronizedList(), SynchronizedSet()等方法,来将集合包装成线程安全的集合。下面是Collections将普通集合包装成线程安全集合的用法, Collection c = Collections.synchronizedCollection(new ArrayList()); List list = Collections.synchronizedList(new ArrayList()); Set s = Collections.synchronizedSet(new HashSet()); Map m = Collections.synchronizedMap(new HashMap());
////或者继承RuntimeException(运行时异常)
public class MyException extends RuntimeException{
private static final long serialVersionUID = 1L;
// 提供无参数的构造方法
public MyException() {
}
// 提供一个有参数的构造方法,可自动生成
public MyException(String message) {
super(message);// 把参数传递给Throwable的带String参数的构造方法
}
}
public class CheckScore {
// 检查分数合法性的方法check() 如果定义的是运行时异常就不用抛异常了
public void check(int score) throws MyException {// 抛出自己的异常类
if (score > 120 || score < 0) {
// 分数不合法时抛出异常
throw new MyException("分数不合法,分数应该是0--120之间");// new一个自己的异常类
} else {
System.out.println("分数合法,你的分数是" + score);
}
}
}
public static void fun3(){
Scanner sc = new Scanner(System.in);
int score = sc.nextInt();
CheckScore check = new CheckScore();
try {
check.check(score);
} catch (MyException e) {// 用自己的异常类来捕获异常
e.printStackTrace();
}
}
Input: 200 Output: com.kunzhuo.xuechelang.test.MyException: 分数不合法,分数应该是0–120之间 at com.kunzhuo.xuechelang.test.CheckScore.check(CheckScore.java:18) at com.kunzhuo.xuechelang.test.Test.fun3(Test.java:101) at com.kunzhuo.xuechelang.test.Test.main(Test.java:39)
public class Task implements Runnable{
protected int countDown = 10;
private static int taskCount = 0 ;
private final int id = taskCount++;
public Task(){}
public Task(int countDown){
this.countDown = countDown;
}
public String status(){
return "#"+id+"("+(countDown>0?countDown:"Task!")+"). ";
}
@Override
public void run() {
while(countDown-->0){//变量countDown先减去1,在和0比较看是否大于0的意思。
System.out.print(status());
Thread.yield();
}
}
}
public static void fun1(){
Task task = new Task();
task.run();
}
上面b的Demo 声明线程并将任务附着到该线程上: Thread t = new Thread(new Task()); t.start(); Thread类的start方法就是触发了java的多线程机制,使得java的多线程能够调用该线程 2.生命周期 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。尤其是当线程启动以后,它不可能一直"霸占"着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换 // 开始线程 public void start( ); public void run( ); // 注意:启动线程使用start()方法,而不是run()方法。永远不要调用线程对象的run()方法。调用start0方法来启动线程,系统会把该run()方法当成线程执行体来处理;但如果直按调用线程对象的run()方法,则run()方法立即就会被执行,而且在run()方法返回之前其他线程无法并发执行。 也就是说,系统把线程对象当成一个普通对象,而run()方法也是一个普通方法,而不是线程执行体。需要指出的是,调用了线程的run()方法之后,该线程已经不再处于新建状态,不要再次调用线程对象的start()方法。只能对处于新建状态的线程调用start()方法,否则将引发IllegaIThreadStateExccption异常。
// 挂起和唤醒线程
public void resume( ); // 不建议使用
public void suspend( ); // 不建议使用
public static void sleep(long millis);
public static void sleep(long millis, int nanos);
public final native void wait() throws InterruptedException;
public final native void notify();
public final native void notifyAll();
// 终止线程
public void stop( ); // 不建议使用
public void interrupt( );
// 得到线程状态
public boolean isAlive( );
public boolean isInterrupted( );
public static boolean interrupted( );
// join方法
public void join( ) throws InterruptedException; //保证线程的run方法完成后程序才继续运行
1).新建和就绪状态 当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时它和其他的Java对象一样,仅仅由Java虚拟机为其分配内存,并初始化其成员变量的值。此时的线程对象没有表现出任何线程的动态特征,程序也不会执行线程的线程执行体。 当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,处于这个状态中的线程并没有开始运行,只是表示该线程可以运行了。至于该线程何时开始运行,取决于JVM里线程调度器的调度。 调用线程对象的start()方法之后,该线程立即进入就绪状态——就绪状态相当于"等待执行",但该线程并未真正进入运行状态。如果希望调用子线程的start()方法后子线程立即开始执行,程序可以使用Thread.sleep(1) 来让当前运行的线程(主线程)睡眠1毫秒,1毫秒就够了,因为在这1毫秒内CPU不会空闲,它会去执行另一个处于就绪状态的线程,这样就可以让子线程立即开始执行。 2).运行和阻塞状态 如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态。 如果计算机只有一个CPU,那么在任何时刻只有一个线程处于运行状态,当然在一个多处理器的机器上,将会有多个线程并行执行; 当线程数大于处理器数时,依然会存在多个线程在同一个CPU上轮换的现象。 3).线程阻塞 当发生如下情况时,线程会进入阻塞状态 a. 线程调用sleep()方法主动放弃所占用的处理器资源 b. 线程调用了一个阻塞式IO方法,在该方法返回之前,该线程被阻塞 c. 线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有。关于同步监视器的知识、后面将存更深入的介绍 d. 线程在等待某个通知(notify) e. 程序调用了线程的suspend()方法将该线程挂起。但这个方法容易导致死锁,所以应该尽量避免使用该方法 4).终止线程的三种方法 有三种方法可以使终止线程。 a. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。 b. 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。 c. 使用interrupt方法中断线程。 3.Lock 1).Lock和synchronized概念和区别 a.synchronized synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法。Synchronized的作用主要有三个: (1)确保线程互斥的访问同步代码 (2)保证共享变量的修改能够及时可见 (3)有效解决重排序问题。 普通同步方法,锁死当前实例对象: Demo:
public class SynchronizedTest {
int a = 0;
public synchronized void method1() {
a++;
System.out.println("Method 1 start" + a);
try {
a++;
System.out.println("Method 1 execute" + a);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
a++;
System.out.println("Method 1 end" + a);
}
public synchronized void method2() {
a++;
System.out.println("Method 2 start" + a);
try {
a++;
System.out.println("Method 2 execute" + a);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
a++;
System.out.println("Method 2 end" + a);
}
public static void main(String[] args) {
final SynchronizedTest test = new SynchronizedTest();
new Thread(new Runnable() {
@Override public void run() {
test.method1();
}
}).start();
new Thread(new Runnable() {
@Override public void run() {
test.method2();
}
}).start();
}
}
lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()是用来获取锁的。unLock()方法是用来释放锁的。 lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。 由于在前面讲到如果采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。通常使用Lock来进行同步的话,是以下面这种形式去使用的:
public static void fun1(){
Lock lock = new ReentrantLock(true);
lock.lock();
try{
//处理任务
System.out.print("vgfsdzxc");
}catch(Exception ex){
}finally{
lock.unlock(); //释放锁
}
}
tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。 tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。
public class Test{ private List arrayList = new ArrayList<>(); Lock lock = new ReentrantLock(); //注意这个地方 public static void main(String[] args) { final Test test = new Test(); new Thread(){ public void run() { test.insert(Thread.currentThread()); } }.start();
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading.
*/
Lock readLock();
/**
* Returns the lock used for writing.
*
* @return the lock used for writing.
*/
Lock writeLock();
}
public class Test {
public static void main(String[] args) {
final Test test = new Test();
new Thread(){
public void run() {
test.get(Thread.currentThread());
};
}.start();
new Thread(){
public void run() {
test.get(Thread.currentThread());
};
}.start();
}
public synchronized void get(Thread thread) {
long start = System.currentTimeMillis();
while(System.currentTimeMillis() - start <= 1) {
System.out.println(thread.getName()+"正在进行读操作");
}
System.out.println(thread.getName()+"读操作完毕");
}
}
public class Test {
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
public static void main(String[] args) {
final Test test = new Test();
new Thread(){
public void run() {
test.get(Thread.currentThread());
};
}.start();
new Thread(){
public void run() {
test.get(Thread.currentThread());
};
}.start();
}
public void get(Thread thread) {
rwl.readLock().lock();
try {
long start = System.currentTimeMillis();
while(System.currentTimeMillis() - start <= 1) {
System.out.println(thread.getName()+"正在进行读操作");
}
System.out.println(thread.getName()+"读操作完毕");
}finally {
rwl.readLock().unlock();
}
}
}
class Bank {
private AtomicInteger account = new AtomicInteger(100);
public AtomicInteger getAccount() {
return account;
}
public void save(int money) {
account.addAndGet(money);
}
}
public static void main(String[] args){
MyTask myTask = new MyTask();
ExecutorService es = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10 ; i++) {
es.submit(myTask);
}
}
public static void main(String[] args){
MyTask myTask = new MyTask();
ExecutorService es = Executors.newCachedThreadPool();
for (int i = 0; i < 10 ; i++) {
es.submit(myTask);
}
}
/**
* 1,corePoolSize:指定线程池中活跃的线程数量
* 2,maximumPoolSize:指定线程池中最大线程数量
* 3,keepAliveTime:超过corePoolSize个多余线程的存活时间
* 4,unit:keepAliveTime的时间单位
* 5,workQueue:任务队列,被提交但尚未被执行的任务
* 6,threadFactory:线程工厂,用于创建线程
* 7,handler拒绝策略:当任务太多来不及处理时,如何拒绝任务
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
/**
* 三步:1,创建线程直到corePoolSize;2,加入任务队列;3,如果还是执行不过来,则执行拒绝策略
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
b.workQueue,当任务被提交但尚未被执行的任务队列,是一个BlockingQueue接口的对象,只存放Runnable对象 根据队列功能分类,看下JDK提供的几种BlockingQueue: SynchronousQueue:直接提交队列:没有容量,每一个插入操作都要等待一个相应的删除操作。通常使用需要将maximumPoolSize的值设置很大,否则很容易触发拒绝策略。 ArrayBlockingQueue:有界的任务队列:任务大小通过入参 int capacity决定,当填满队列后才会创建大于corePoolSize的线程。 LinkedBlockingQueue:无界的任务队列:线程个数最大为corePoolSize,如果任务过多,则不断扩充队列,知道内存资源耗尽。 PriorityBlockingQueue:优先任务队列:是一个无界的特殊队列,可以控制任务执行的先后顺序,而上边几个都是先进先出的策略。
c.ThreadFactory是用来创建线程池中的线程工厂类
public class ThreadFactoryDemo {
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
@Override public Thread newThread(@NonNull Runnable runnable) {
Thread t = new Thread(group, runnable,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
public static class MyTask implements Runnable{
public void run() {
System.out.println(System.currentTimeMillis() + " Thread Name:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MyTask myTask = new MyTask();
ExecutorService es = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(), new DefaultThreadFactory() {//LinkedBlockingQueue 无界的任务队列:线程个数最大为corePoolSize,如果任务过多,则不断扩充队列,知道内存资源耗尽。
public Thread newThread(Runnable r) {
Thread t =new Thread(r);
t.setDaemon(true);
System.out.println(System.currentTimeMillis() + " create thread:" + t.getName());
return t;
}
});
for (int i = 0; i < 10 ; i++) {
es.submit(myTask);
}
}
}
public class ExceptionThreadPoolDemo {
public static class MyTask implements Runnable {
int a, b;
public MyTask(int a, int b) {
this.a = a;
this.b = b;
}
public void run() {
double re = a / b;
System.out.println(re);
}
}
public static void main(String[] args) {
//ExecutorService es = new TraceThreadPoolExecutor(0,Integer.MAX_VALUE,0L, TimeUnit.SECONDS,new SynchronousQueue());
ExecutorService es = new ThreadPoolExecutor(0,Integer.MAX_VALUE,0L, TimeUnit.SECONDS,new SynchronousQueue());
for (int i = 0; i < 5; i++) {
//不进行日志打印
//es.submit(new MyTask(100,i));
//进行日志打印,只是打印了具体方法错误:Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
// at com.ljh.thread.thread_pool.ExceptionThreadPoolDemo$MyTask.run(ExceptionThreadPoolDemo.java:24)
// at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
// at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
// at java.lang.Thread.run(Thread.java:748)
//es.submit(new MyTask(100,i));
es.execute(new MyTask(100, i));
}
}
}
public class TraceThreadPoolExecutor extends ThreadPoolExecutor {
public TraceThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
public void execute(Runnable command) {
super.execute(wrap(command,clientTrace(),Thread.currentThread().getName()));
}
private Runnable wrap(final Runnable command, final Exception clientTrace, String Threadname) {
return new Runnable(){
@Override
public void run() {
try{
command.run();//执行原本任务捕获异常
}catch(Exception e){
clientTrace.printStackTrace();
throw e;// 抛出原本任务的异常
}
}
};
}
private Exception clientTrace() {
return new Exception("Client stack trace");
}
@Override
public Future> submit(Runnable task) {
return super.submit(wrap(task,clientTrace(),Thread.currentThread().getName()));
}
}
main方法
public static void main(String[] args) {
ExecutorService es = new TraceThreadPoolExecutor(0,Integer.MAX_VALUE,0L, TimeUnit.SECONDS,new SynchronousQueue());
for (int i = 0; i < 5; i++) {
//es.submit(new MyTask(100,i));
es.execute(new MyTask(100, i));
}
}
public class TestAtomicDemo {
public static void main(String[] args){
AtomicDemo ad = new AtomicDemo();
for(int i=0; i < 10; i++){
new Thread(ad).start();
}
}
}
class AtomicDemo implements Runnable{
private AtomicInteger atomicInteger = new AtomicInteger(0);
public void run(){
try{
Thread.sleep(200);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName() + ":" + getSerialNumber());
}
public int getSerialNumber(){
return atomicInteger.getAndIncrement();//原子变量的自增运算
}
}
b.CAS算法:Compare and Swap比较并交换。总共由三个操作数,一个内存值v,一个线程本地内存旧值a(期望操作前的值)和一个新值b,在操作期间先拿旧值a和内存值v比较有没有发生变化,如果没有发生变化,才能内存值v更新成新值b,发生了变化则不交换。 CAS虽然很高效的解决原子操作,但是CAS仍然存在三大问题:ABA问题、循环时间长开销大、只能保证一个共享变量的原子操作。 4).并发容器 a.ConcurrentHashMap ConcurrentHashMap它引入了一个“分段锁”的概念,具体可以理解为把一个大的Map拆分成N个小的HashTable,根据key.hashCode()来决定把key放到哪个HashTable中 ConcurrentHashMap和HashMap的比较:Hashmap是哈希表的map实现,可操作null键和null值,是非线程安全的,ConcurrentHashMap 是线程安全的;储存方式是:key所对应的value值链接成一个链表,而数组中储存的是链表第一个节点的地址值,所以hashmap又叫链表的数组。hashmap的性能受两个因素的影响,初始容量和加载因子,若hash表中的条目数超过初始值和加载因子的乘积,那么hash表将做出自我调整,将容量扩充为原来的两倍,并将原有的数据重新映射到表中,这个操作叫做rehash,容量扩充,重新映射,所以说rehash必将会造成时间和空间的开销,所以说初始容量和加载因子会影响hashmap的性能。 b.CountDownLatch(闭锁)是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待;
public class TestCountDownLatch {
// 主线程等待子线程执行完,然后执行计时操作
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(10);//10就是实际上就是闭锁需要等待的线程数量
LatchDemo ld = new LatchDemo(latch);
long start = System.currentTimeMillis();
// 创建10个线程
for (int i = 0; i < 10; i++) {
new Thread(ld).start();
}
try {
latch.await();//与CountDownLatch的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。 这样就达到计时的效果
} catch (InterruptedException e) {
}
long end = System.currentTimeMillis();
System.out.println("耗费时间为:" + (end - start));
}
}
class LatchDemo implements Runnable {
private CountDownLatch latch;
// 有参构造器
public LatchDemo(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
synchronized (this) {
try {
// 打印50000以内的偶数
for (int i = 0; i < 50000; i++) {
if (i % 2 == 0) {
System.out.println(i + " " + Thread.currentThread().getName());
}
}
} finally {
// 线程数量递减
latch.countDown();
}
}
}
}
五.IO(字节流、字符流、转换流、文件) 1.字节流 1).InputStream/OutPutStream - - -字节流基类 你把你自己想象为是一个程序,InputStream对你来说是输入,也就是你要从某个地方读到自己这来,而OutputStream对你来说就是输出,也就是说你需要写到某个地方 a.InputStream 此抽象类是表示字节输入流的所有类的超类。需要定义 InputStream 的子类的应用程序必须始终提供返回下一个输入字节的方法 int available() 返回此输入流方法的下一个调用方可以不受阻塞地从此输入流读取(或跳过)的字节数。 void close() 关闭此输入流并释放与该流关联的所有系统资源。 void mark(int readlimit) 在此输入流中标记当前的位置。 boolean markSupported() 测试此输入流是否支持 mark 和 reset 方法。 abstract int read() 从输入流读取下一个数据字节。 int read(byte[] b) 从输入流中读取一定数量的字节并将其存储在缓冲区数组 b 中。 int read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入字节数组。 void reset() 将此流重新定位到对此输入流最后调用 mark 方法时的位置。 long skip(long n) 跳过和放弃此输入流中的 n 个数据字节。
b.OutputStream 此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。需要定义OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。 void close() 关闭此输出流并释放与此流有关的所有系统资源。 void flush() 刷新此输出流并强制写出所有缓冲的输出字节。 void write(byte[] b) 将 b.length 个字节从指定的字节数组写入此输出流。 void write(byte[] b, int off, int len) 将指定字节数组中从偏移量 off 开始的 len 个字节写入此输出流。 abstract void write(int b) 将指定的字节写入此输出流。 进行I/O操作时可能会产生I/O例外,属于非运行时例外,应该在程序中处理。如:FileNotFoundException, EOFException, IOException等等,下面具体说明操作JAVA字节流的方法。
public class ByteArrayInputStreamDemo {
public static void main(String[] args)throws Exception{
Data data = new Data();
byte[] temp = data.getData();
InputStream inputStream = new ByteArrayInputStream(temp);
byte[] arr =new byte[temp.length];
inputStream.read(arr);
System.out.println(new String(arr));
}
}
class Data{
byte[] data = "abc".getBytes();
public byte[] getData() {
returndata;
}
}
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("TestFile.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c = bis.read();//读取bis流中的下一个字节
while (c != -1) {
baos.write(c);
c = bis.read();
}
bis.close();
byte retArr[] = baos.toByteArray();
System.out.println(new String(retArr));
}
public class Send {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();//通过DatagramSocket对象创建udp服务
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));//从键盘上面输入文本
String line = null;
while((line=bufr.readLine())!=null)//当输入不为空时
{
if("byebye".equals(line))//当输入为byebye时退出程序
break;
//确定好数据后,并把数据封装成数据包
byte[] buf = line.getBytes();
DatagramPacket dp =
new DatagramPacket(buf,buf.length, InetAddress.getByName("127.0.0.1"),30000);//发送至指定IP,指定端口
ds.send(dp);//通过send方法将数据包发送出去
}
ds.close();//关闭资源
}
}
接收端
public class Receive {
public static void main(String[] args) throws Exception
{
@SuppressWarnings("resource")
DatagramSocket ds = new DatagramSocket(30000);//接收端监听指定端口
while(true)
{
//定义数据包,用于存储数据
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);//通过服务的receive方法将收到数据存入数据包中,receive()为阻塞式方法,接收到数据报之前会一直阻塞
//通过数据包的方法获取其中的数据
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
System.out.println(ip+"::"+data);
}
}
}
3.TCP传输 Socket的使用就是TCP传输的基本用法;见上1 4.UDP传输和TCP传输的比较 UDP通讯协议的特点:(DatagramPacket和 DatagramSocket) a. 将数据极封装为数据包,面向无连接。 b. 每个数据包大小限制在64K中 c.因为无连接,所以不可靠 d. 因为不需要建立连接,所以速度快 e.udp 通讯是不分服务端与客户端的,只分发送端与接收端。
TCP通讯协议特点:(Socket和ServerScocket)
a. tcp是基于IO流进行数据 的传输 的,面向连接。
b. tcp进行数据传输的时候是没有大小限制的。
c. tcp是面向连接,通过三次握手的机制保证数据的完整性。 可靠协议。
d. tcp是面向连接的,所以速度慢。
e. tcp是区分客户端与服务端 的。
顺便附上我们在利用JAVA写两个协议的过程:
UDP:
发送端的使用步骤:
a. 建立udp的服务。
b. 准备数据,把数据封装到数据包中发送。 发送端的数据包要带上ip地址与端口号。
c. 调用udp的服务,发送数据。
d. 关闭资源。
接收端的使用步骤:
a. 建立udp的服务
b. 准备空 的数据 包接收数据。
c. 调用udp的服务接收数据。
d. 关闭资源
TCP:
tcp的客户端使用步骤:
a. 建立tcp的客户端服务。
b. 获取到对应的流对象。
c.写出或读取数据
d. 关闭资源。
ServerSocket的使用 步骤:
a. 建立tcp服务端 的服务。
b. 接受客户端的连接产生一个Socket.
c. 获取对应的流对象读取或者写出数据。
d. 关闭资源。
5.Http协议 1).介绍 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写。它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的RFC,RFC 1945定义了HTTP/1.0版本。其中最著名的就是RFC 2616。RFC 2616定义了今天普遍使用的一个版本——HTTP 1.1。 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。 HTTP协议是一个传输层基于TCP的应用层协议! 2).利用java代码测试各个协议头 一个完整的http协议包括请求和响应, 注意:使用HTTP协议,无法实现在客户端没有发起请求的时候,服务器将消息推送给客户端. a.请求篇 http请求由三部分组成,分别是:请求行、消息报头、请求正文 请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:Method Request-URI HTTP-Version CRLF 其中 Method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符)。 请求方法(所有方法全为大写)有多种,各个方法的解释如下: GET 请求获取Request-URI所标识的资源 POST 在Request-URI所标识的资源后附加新的数据 HEAD 请求获取由Request-URI所标识的资源的响应消息报头 PUT 请求服务器存储一个资源,并用Request-URI作为其标识 DELETE 请求服务器删除Request-URI所标识的资源 TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断 CONNECT 保留将来使用 OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求 b.响应篇 响应消息包括状态行、若干头部行和附属体(html数据实体)。 状态行 状态行包括:HTTP协议版本号、状态码、状态码的文本描述信息。如:HTTP/1.1 200 OK 状态码由一个三位数组成,状态码大体有5种含义: 1. 1xx。信息,请求收到,继续处理。 2. 2xx。成功。200请求成功;206断点续传。 3. 3xx。重定向。一般跳转到新的地址。 4. 4xx。客户端错误。404文件不存在 5. 5xx。服务器错误。500内部错误。
常见状态代码、状态描述、说明:
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
eg:HTTP/1.1 200 OK (CRLF)
头部行
Set-Cookie:服务器设置客户端Cookie。设置格式是name=value,设置多个参数时中间用分号隔开。Set-Cookie时还会用到几个参数:PATH设置有效的路径,DOMAIN设置cookie生效的域名,Expire设置cookie的有效时间,0表示关闭浏览器就失效。
Location:当服务器返回3xx重定向时,该参数实现重定向。广告链接的跳转就使用这种协议。
Content-Length:附属体(数据实体)的长度
3).java中的Http通信 a.使用HTTP的Get方式读取网络数据
public class ReadByGet extends Thread {
@Override public void run() {
try {
//如果有参数,在网址中携带参数
URL url = new URL("http://gank.io/api/today");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
//伪造一下UA就可以了
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36)");
InputStream is = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
int responsecode = conn.getResponseCode();
if(responsecode == 200){
String line;
StringBuilder builder = new StringBuilder();
while((line=br.readLine())!=null){
builder.append(line);
}
br.close();
isr.close();
is.close();
System.out.println(builder.toString());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ReadByGet().start();
}
}
b.使用HTTP的Post方式与网络交互通信
public class ReadByPost extends Thread {
@Override public void run() {
try {
URL url = new URL("网址");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.addRequestProperty("encoding", "UTF-8");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
OutputStream os = conn.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
bw.write("");
bw.flush();
InputStream is = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
StringBuilder builder = new StringBuilder();
while ((line = br.readLine()) != null) {
builder.append(line);
}
//关闭资源
System.out.println(builder.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main() {
new ReadByPost().start();
}
}
c.使用HttpClient进行Get方式通信,apache有一个HttpClient包
public class Get extends Thread {
@Override public void run() {
HttpClient client = HttpClients.createDefault();
HttpGet get = new HttpGet("http://gank.io/api/today");
try {
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "UTF-8");
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Get().start();
}
}
d.使用HttpClient进行Post方式通信
public class Post extends Thread {
HttpClient client = HttpClients.createDefault();
@Override public void run() {
HttpPost post = new HttpPost("网址");
//设置要传的参数
List parameters = new ArrayList();
parameters.add(new BasicNameValuePair("key", "value"));
try {
post.setEntity(new UrlEncodedFormEntity(parameters, "UTF-8"));
HttpResponse response = client.execute(post);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "UTF-8");
System.out.println(result);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Post().start();
}
}
/*android {
//声明 使用
useLibrary 'org.apache.http.legacy'
}
dependencies {
implementation 'org.apache.httpcomponents:httpclient-android:4.3.5.1'
}*/
public class TestMain {
public static void main(String[] args) {
System.out.println(XYZ.name);
}
static class XYZ {
public static String name = "luoxn28";
static {
System.out.println("xyz静态块");
}
public XYZ() {
System.out.println("xyz构造了");
}
}
}
public class TestBase {}
public class TestDriver extends TestBase{}
public class TestMain {
public static void main(String[] args) {
TestBase base = new TestDriver();
if (base instanceof TestDriver) {
// 这里可以向下转换了
System.out.println("ok");
} else {
System.out.println("not ok");
}
}
}
InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。
我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: 指代我们所代理的那个真实对象
method: 指代的是我们所要调用真实对象的某个方法的Method对象
args: 指代的是调用真实对象某个方法时接受的参数
Proxy.newProxyInstance(ClassLoader loader,Class>[] interfaces,InvocationHandler h) throws IllegalArgumentException;
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
Output: com.sun.proxy.$Proxy0 before rent house Method:public abstract void test.Interface.doSomething() doSomething. after rent house before rent house Method:public abstract void test.Interface.somethingElse(java.lang.String) somethingElse luoxn28 after rent house
public class Generic{
//key这个成员变量的类型为T,T的类型由外部指定
private T key;
public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
this.key = key;
}
public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
return key;
}
}
public class Main {
public static void main(String[] args) {
//泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
//传入的实参类型需与泛型的类型参数类型相同,即为Integer.
Generic genericInteger = new Generic(123456);
//传入的实参类型需与泛型的类型参数类型相同,即为String.
Generic genericString = new Generic("key_vlaue");
System.out.println("泛型测试 "+"key is " + genericInteger.getKey());
System.out.println("泛型测试 "+"key is " + genericString.getKey());
}
}
public class Main {
public static void showKeyValue(Generic> obj){
System.out.println("泛型测试 "+"key value is " + obj.getKey());
}
public static void main(String[] args) {
Generic gInteger = new Generic(123);
Generic gNumber = new Generic(456);
showKeyValue(gNumber);
//showKeyValue(Generic obj)
// showKeyValue这个方法编译器会为我们报错:Generic
// cannot be applied to Generic
showKeyValue(gInteger);
}
}
/**
* public 与 返回值中间非常重要,可以理解为声明此方法为泛型方法。
* 只有声明了等的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
* 表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
* 与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
*/
public class GenericMethods {
public void genericMethod1(T t){
System.out.println(t.getClass().getName());
}
public T genericMethod2( Class tClass ) throws InstantiationException ,
IllegalAccessException {
T t = tClass.newInstance();
return t;
}
public static void genericMethod3( T[] inputArray ) {
// 输出数组元素
for ( T element : inputArray ){
System.out.printf( "%s ", element );
}
}
}
public class Main {
public void printArgs( T... args ){
for(T t : args){
System.out.println(t + " ");
}
}
public static List toList(T... args){
List result = new ArrayList();
for(T item:args)
result.add(item);
return result;
}
public static void main(String[] args) {
Main gmt = new Main();
gmt.printArgs("A","B"); // A B
List ls = Main.toList("A", "vcwasd");
System.out.println(ls); // [A]
ls = Main.toList("A","B","C");
System.out.println(ls); // [A,B,C]
}
}
GetUrlParam:function GetUrlParam(param){
var reg = new RegExp("(^|&)"+ param +"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if(r!=null
==================================================
1、打开PowerDesigner12,在菜单中按照如下方式进行操作
file->Reverse Engineer->DataBase
点击后,弹出 New Physical Data Model 的对话框
2、在General选项卡中
Model name:模板名字,自
网站配置是apache+tomcat,tomcat没有报错,apache报错是:
The proxy server received an invalid response from an upstream server. The proxy server could not handle the request GET /. Reason: Error reading fr
Free variable A free variable of an expression is a variable that’s used inside the expression but not defined inside the expression. For instance, in the function literal expression (x: Int) => (x
Part Ⅰ:
《阿甘正传》Forrest Gump经典中英文对白
Forrest: Hello! My names Forrest. Forrest Gump. You wanna Chocolate? I could eat about a million and a half othese. My momma always said life was like a box ochocol
Json在数据传输中很好用,原因是JSON 比 XML 更小、更快,更易解析。
在Java程序中,如何使用处理JSON,现在有很多工具可以处理,比较流行常用的是google的gson和alibaba的fastjson,具体使用如下:
1、读取json然后处理
class ReadJSON
{
public static void main(String[] args)