J2SE基础~3
开心一刻:今天公司让我接待,新入职的女孩,我看着她的简历,边走边聊:你今年本命年!女孩惊悚的望着我,并用手护住屁股说:你看见我裤衩了? 呜呜 好邪恶~
此篇文章为了控制篇幅,多提供了几个外链~~
下面正式进入干货区,喜欢的话、双击、评论、转发,动一动你的小手让更多的人知道!关注帅比~杨
实现多线程的两种方法:Thread与Runable。
线程同步的方法:sychronized、lock、reentrantLock等。
锁的等级:方法锁、对象锁、类锁。
写出生产者消费者模式。
ThreadLocal的设计理念与作用。
ThreadPool用法与优势。
Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。
wait()和sleep()的区别。
foreach与正常for循环效率对比。
Java IO与NIO。
反射的作用与原理。
泛型常用特点,List能否转为List。
解析XML的几种方式的原理与特点:DOM、SAX、PULL。
Java与C++对比。
Java1.7与1.8新特性。
设计模式:单例、工厂、适配器、责任链、观察者等等。
JNI的使用。
1. 实现多线程的两种方法:Thread与Runable。
java实现多线程有两种方法
- 继承Thread类
- 实现Runnable接口
**ps: ***不论用哪种方法,都必须用Thread(如果是Thead子类就用它本身)产生线程,然后再调用start()方法。
继承Thread类有一个缺点就是单继承,而实现Runnable接口则弥补了它的缺点,可以实现多继承
继承Thread类如果产生Runnable实例对象,就必须产生多个Runnable实例对象,然后再用Thread产生多个线程;而实现Runnable接口,只需要建立一个实现这个类的实例,然后用这一个实例对象产生多个线程。
2. 线程同步的方法:sychronized、lock、reentrantLock等。
synchronized可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。
lock:需要显示指定起始位置和终止位置。一般使用ReentrantLock类做为锁,多个线程中必须要使用一个ReentrantLock类做为对象才能保证锁的生效。且在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。
详细的使用说明请戳: https://my.oschina.net/softwarechina/blog/170859
3. 锁的等级:方法锁、对象锁、类锁。
方法锁:
通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。
ps:最常见的一种方法锁形式:
public synchronized void method() {
System.out.println("我是对象锁也是方法锁");
}
对象锁:
对象锁(synchronized修饰方法或代码块)当一个类中有synchronized method或synchronized block的时候调用此类的此方法或进入其同步区域时,就必须先获得对象锁。如果此类的对象锁已被其他调用者占用,则需要等待此锁被释放。(方法锁也可以是对象锁,非static修饰的函数),下面给出简单示例:
public synchronized void method1() {
// 同步方法
System.out.println("对象锁:方式一");
}
public void method2() {
// 同步代码块
synchronized (this) {
System.out.println("对象锁:方式二");
}
}
类锁:(synchronized 修饰静态的方法或代码块)由于一个class不论被实例化多少次,其中的静态方法和静态变量在内存中都只有一份。所以,一旦一个静态的方法被申明为synchronized。此类所有的实例化对象在调用此方法,共用同一把锁,我们称之为类锁。简单示例:
public static synchronized void method1() {
System.out.println("类锁:方式一");
}
public void method2() {
synchronized (Trhead_.class) {
System.out.println("类锁:方式二");
}
}
4. 写出生产者消费者模式。
很形象很用心的文章 http://www.jianshu.com/p/0d1c950e6614 但均为提供demo这里提供的只是编程思想,拒绝伸手党,提高自己的编程能力是做编程最基本的原则,所以此时此刻努力吧。淡化你的“cv”大法,关注帅比-杨~~从这里出发!
5. ThreadLocal的设计理念与作用。
ThreadLocal提供了一种解决多线程并发问题的方案。此类在维护变量时,实际使用了当前线程(Thread)中的一个叫做ThreadLocalMap的独立副本,每个线程可以独立修改属于自己的副本而不会互相影响,从而隔离了线程和线程,避免了线程访问实例变量发生冲突的问题。ThreadLocal本身并不是一个线程,而是通过操作当前线程(Thread)中的一个内部变量来达到与其他线程隔离的目的.之所以取名为ThreadLocal,所期望表达的含义是其操作的对象是线程(Thread)的一个本地变量.如果我们看一下Thread的源码实现,就会发现这一变量,代码如下:
public class Thread implements Runnable {
// 这里省略了许多其他的代码
ThreadLocal.ThreadLocalMap threadLocals = null;
}
这是JDK中Thread源码的一部分,从中我们可以看出ThreadLocalMap跟随着当前的线程而存在.不同的线程Thread,拥有不同的ThreadLocalMap的本地实例变量,这也就是“副本”的含义
如果想了解的更详细请戳这里:http://blog.csdn.net/hua286306956/article/details/8660268
6. ThreadPool用法与优势。
ThreadPool理解过来就是线程池,合理利用线程池能够带来三个好处:
1> 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
2> 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
3> 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
简单用法如下:
/**
* 创建一个带有固定线程的线程池
*/
public static void displayThreadPool() {
// 创建一个带有4个固定线程的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(4);
distributeTaskForThreadPool(threadPool);
}
/**
* 为线程池分配8个任务,使其驱动
*
* @param threadPool
*/
public static void distributeTaskForThreadPool(ExecutorService threadPool) {
// 让线程池驱动8个任务
for (int i = 1; i <= 8; i++) {
// 由于内部类里面不能放一个非final的变量,所以我把i的值赋予task
final int task = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println("我是" + Thread.currentThread().getName()
+ "," + "拿到了第" + task + "个任务,我开始执行了");
}
});
}
}
7. Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。
ArrayBlockingQueue: 一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部是在队列中存在时间最长的元素。队列的尾部是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列检索操作则是从队列头部开始获得元素。
CountDownLatch: 从名字可以看出,CountDownLatch是一个倒数计数的锁,当倒数到0时触发事件,也就是开锁,其他人就可以进入了。在一些应用场合中,需要等待某个条件达到要求后才能做后面的事情;同时当线程都完成后也会触发事件,以便进行后面的操作。
CountDownLatch最重要的方法是countDown()和await(),前者主要是倒数一次,后者是等待倒数到0,如果没有到达0,就只有阻塞等待了。
详情: http://blog.csdn.net/hikvision_java_gyh/article/details/9953691
8. wait()和sleep()的区别。
wait是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去机锁,wait(long timeout)超时时间到后还需要返还对象锁);其他线程可以访问;wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。wiat()必须放在synchronized block中,否则会在program runtime时扔出”java.lang.IllegalMonitorStateException“异常。
sleep: 使当前线程进入停滞状态(阻塞当前线程),让出CUP的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会; sleep()是Thread类的Static(静态)的方法;因此他不能改变对象的机锁,所以当在一个Synchronized块中调用Sleep()方法是,线程虽然休眠了,但是对象的机锁并木有被释放,其他线程无法访问这个对象(即使睡着也持有对象锁)。在sleep()休眠时间期满后,该线程不一定会立即执行,这是因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级。
sleep()和wait()方法的最大区别是:sleep()睡眠时,保持对象锁,仍然占有该锁;而wait()睡眠时,释放对象锁。但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException(但不建议使用该方法)。
9. foreach与正常for循环效率对比。
首先介绍一下:foreach语句是java5的新特征之一,是for语句的简化版本。在遍历数组、集合方面foreach为开发人员提供了极大的方便(主要体现在代码简化)。然而foreach语句并不能完全取代for语句,且任何的foreach语句都可以改写为for语句版本,这个只有亲自动过手的小伙伴才知道。 由于篇幅问题这里就不贴测试代码了,想认真研究的就打开你的电脑亲自动手敲一下运行看效果,编程是一种以动手为美的工作,你还不动手!?
通过实际动测试可以得出:循环ArrayList时,普通for循环比foreach循环花费的时间要少一点;循环LinkList时,普通for循环比foreach循环花费的时间要多很多。
当我们将循环次数提升到一百万次的时候,循环ArrayList,普通for循环还是比foreach要快一点;但是普通for循环在循环LinkList时,程序直逼卡死。
结论:需要循环数组结构的数据时,建议使用普通for循环,因为for循环采用下标访问,对于数组结构的数据来说,采用下标访问比较好。需要循环链表结构的数据时,一定不要使用普通for循环,这种做法很糟糕,数据量大的时候有可能会导致系统崩溃。
10. Java IO与NIO。
IO: IO大致可以分为本地IO(磁盘IO)和网络IO。所谓的本地IO,即本地的应用程序从磁盘里面读写数据,不涉及网络的概念;而网络IO则是发送端发送数据(写),接收端接收数据(读)。
NIO:NIO,即 Non-blocking IO,非阻塞式的IO,上面讲的IO都是阻塞式的。什么是阻塞式的?就是你如果要从磁盘上读取一个文件,在读的过程中你不能干其他事,只有等待它读取完毕,你才能干后面的事情;而非阻塞式,显然,就可以在读取文件的过程中,做别的事情。
未完待续~~~
ps: 喜欢有帮助的话: 喜欢、评论、转发,动一动你的小手让更多的人知道!关注 帅比-杨