1.有synchronized的地方不一定有wait,notify
2.有wait,notify的地方必有synchronized.这是因为wait和notify不是属于线程类,而是每一个对象都具有的方法 (事实上,这两个方法是Object类里的),而且,这两个方法都和对象锁有关,有锁的地方,必有synchronized。
为什么有wait,notify的地方必有synchronized?
synchronized方法中由当前线程占有锁。另一方面,调用wait()notify()方法的对象上的锁必须为当前线程所拥有。因 此,wait()notify()方法调用必须放置在synchronized方法中,synchronized方法的上锁对象就是调用 wait()notify()方法的对象。若不满足这一条件,则程序虽然仍能编译,但在运行时会出现IllegalMonitorStateException 异常。
ThreadLocal(提供了线程本地的变量)和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区 别,synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本, 使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
synchronized有什么缺点:
1. 只有一个condition与锁相关联,这个condition是什么?就是synchronized对针对的对象锁。
2. 多线程竞争一个锁时,其余未得到锁的线程只能不停的尝试获得锁,而不能中断。这种情况对于大量的竞争线程会造成 性能的下降等后果。
一个ReentrantLock可以有多个Condition实例。
举个例子,还是刚才说的ArrayBlockingQueue类,看看源码(节选):
- public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable {
- ...
- private final ReentrantLock lock;
- private final Condition notEmpty;
- private final Condition notFull;
- ...
- public ArrayBlockingQueue(int capacity, boolean fair) {
- ...
- lock = new ReentrantLock(fair);
- notEmpty = lock.newCondition();
- notFull = lock.newCondition(); //为该ReentrantLock设置了两个Condition
- }
- public E take() throws InterruptedException {
- final ReentrantLock lock = this.lock;
- lock.lockInterruptibly();
- try {
- try {
- while (count == 0)
- notEmpty.await(); //这里针对notEmpty这个condition,如果队列为空则线程等待这个条件
- } catch (InterruptedException ie) {
- notEmpty.signal();
- throw ie;
- }
- E x = extract();
- return x;
- } finally {
- lock.unlock();
- }
- }
- private E extract() {
- final E[] items = this.items;
- E x = items[takeIndex];
- items[takeIndex] = null;
- takeIndex = inc(takeIndex);
- --count;
- notFull.signal(); //这里针对notFull这个condition,唤醒因该条件而等待的线程
- return x;
- }
- ...
- }
publicclass ArrayBlockingQueue<E> extends AbstractQueue<E> implementsBlockingQueue<E>, java.io.Serializable {
...
private final ReentrantLock lock;
private final Condition notEmpty;
private final Condition notFull;
...
publicArrayBlockingQueue(int capacity, boolean fair) {
...
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition(); //为该ReentrantLock设置了两个Condition
}
publicE take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
try {
while (count == 0)
notEmpty.await(); //这里针对notEmpty这个condition,如果队列为空则线程等待这个条件
} catch (InterruptedException ie) {
notEmpty.signal();
throw ie;
}
E x = extract();
return x;
}finally {
lock.unlock();
}
}
private E extract() {
final E[] items = this.items;
Ex = items[takeIndex];
items[takeIndex] = null;
takeIndex = inc(takeIndex);
--count;
notFull.signal(); //这里针对notFull这个condition,唤醒因该条件而等待的线程
return x;
}
...
}
这里notEmpty和notFull作为lock的两个条件是可以分别负责管理想要加入元素的线程和想要取出元素的线程。例如put()方法在 元素个数达到最大限制时会使用notFull条件把试图继续插入元素的线程都扔到等待集中,而执行了take()方法时如果顺利进入extract()则会空出空间,这时notFull负责随机的通知被其扔到等待集中的线程执行插入元素的操作。
2. ReentrantLock提供了lockInterruptibly()方法可以优先考虑响应中断,而不是像synchronized那样不响应interrupt()操作。有了这个机制,使用ReentrantLock时就不会像synchronized那样产生死锁了。由于ReentrantLock在提供了多样的同步功能(除了可响应中断,还能设置时间限制),因此在同步比较激烈的情况下,性能比synchronized大大提高。在同步竞争不激烈时用synchronized,激烈时用 ReentrantLock。
- //synchronized
- public synchronized void increment() {
- count++;
- }
- java.util.concurrent.locks.ReentrantLock
- public void increment() {
- lock.lockInterruptibly();//上锁
- try {
- count++;
- } finally {
- lock.unlock();//手动释放锁
- }
- }
1. HashSet概述:
HashSet实现Set接 口,由哈希表(实际上是一个HashMap实例)支持。它不保证set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用null元 素。
2. HashSet的实现:
对于HashSet而言,它是基于HashMap实 现的,HashSet底层使用HashMap来 保存所有元素,因此HashSet的实现比较简单,相关HashSet的 操作,基本上都是直接调用底层HashMap的相关方法来完成
对于HashSet中 保存的对象,请注意正确重写其equals和hashCode方 法,以保证放入的对象的唯一性。
数组是将元素在内存中连续存放,由于每个元素占用内存相同,所以你可以通过下标迅速访问数组中任何元素。但是如果你要在数组中增加一个元素,你需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。同样的道理,如果你想删除一个元素,你同样需要移动大量元素去填掉被移动的元素。
从内存存储来看 (静态)数组从栈中分配空间, 对于程序员方便快速,但是自由度小
链表从堆中分配空间, 自由度大但是申请管理比较麻烦
临时表和普通表的主要区别有哪些,使用临时表的主要原因是什么?
在Oracle中,可以创建以下两种临时表:
a。会话特有的临时表
CREATE GLOBAL TEMPORARY <TABLE_NAME> (<column specification> )
ON COMMIT PRESERVE ROWS;
b。事务特有的临时表
CREATE GLOBAL TEMPORARY <TABLE_NAME> (<column specification> )
ON COMMIT DELETE ROWS;
CREATE GLOBAL TEMPORARY TABLE MyTempTable
所建的临时表虽然是存在的,但是你试一下insert一条记录然后用别的连接登上去select,记录是空的
--ON COMMIT DELETE ROWS 说明临时表是事务指定,每次提交后ORACLE将截断表(删除全部行)
--ON COMMIT PRESERVE ROWS 说明临时表是会话指定,当中断会话时ORACLE将截断表
有个表a(xnumber(20),y number(20))用最快速高效的SQL向该表插入从1开始的连续的1000万记录。
insert into a(x,y) select rownum,rownum from all_objectswhere rownum<10000000;
commit;
简述SGA主要组成结构和用途?
SGA是Oracle为一个实例分配的一组共享内存缓冲区,它包含该实例的数据和控制信息。SGA在实例启动时被 自动分配,当实例关闭时被收回。数据库的所有数据操作都要通过SGA来进行。
SGA中内存根据存放信息的不同,可以分为如下几个区域:
a.Buffer Cache:存放数据库中数据库块的拷贝。它是由一组缓冲块所组成,这些缓冲块为所有与该实例相链接的用户进程所共享。缓冲块的数目由初始化参数DB_BLOCK_BUFFERS确定,缓冲块的大小由初始化参数DB_BLOCK_SIZE确定。大的数据块可提高查询速度。它由DBWR操作。
b. 日志缓冲区Redo Log Buffer:存放数据操作的更改信息。它们以日志项(redo entry)的形式存放在日志缓冲区中。当需要进行数据库恢复时,日志项用于重构或回滚对数据库所做的变更。日志缓冲区的大小由初始化参数LOG_BUFFER确定。大的日志缓冲区可减少日志文件I/O的次数。后台进程LGWR将日志缓冲区中的信息写入磁盘的日志文件中,可启动ARCH后台 进程进行日志信息归档。
c. 共享池Shared Pool:包含用来处理的SQL语句信息。它包含共享SQL区和数据字典存储区。共享SQL区包含执行特定的SQL语句所用的信息。数据字典区用于存放数 据字典,它为所有用户进程所共享。
在传统的Java应用中,Bean的生命周期非常简单。
Java的关键词new用来实例化Bean(或许他是非序列化的)。这样就够用了。
相反,Bean的生命周期在Spring容器中更加细致。
理解SpringBean的生命周期非常重要,因为你或许要利用Spring提供的机会来订制Bean的创建过程。
1.容器寻找Bean的定义信息并且将其实例化。
2.受用依赖注入,Spring按照Bean定义信息配置Bean的所有属性。
3.如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。
4.如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。
5.如果BeanPostProcessor和Bean关联,那么它们的postProcessBeforeInitialzation()方法 将被调用。
6.如果Bean指定了init-method方法,它将被调用。
7.最后,如果有BeanPsotProcessor和Bean关联,那么它们的postProcessAfterInitialization()方法将被调用。
到这个时候,Bean已经可以被应用系统使用了,并且将被保留在BeanFactory中知道它不再需要。
有两种方法可以把它从BeanFactory中删除掉。
1.如果Bean实现了DisposableBean接口,destory()方法被调用。
2.如果指定了订制的销毁方法,就调用这个方法。
Bean在Spring应用上下文的生命周期与在Bean工厂中的生命周期只有一点不同,
唯一不同的是,如果Bean实现了ApplicationContextAwre接口,setApplicationContext()方法被调 用。
只有singleton行为的bean接受容器管理生命周期。
non-singleton行为的bean,Spring容器仅仅是new的替代,容器只负责创建。
对于singletonbean,Spring容器知道bean何时实例化结束,何时销毁,
Spring可以管理实例化结束之后,和销毁之前的行为,管理bean的生命周期行为主要未如下两个时机:
Bean全部依赖注入之后
Bean即将销毁之前
1)依赖关系注入后的行为实现:
有两种方法:A.编写init方法 B.实现InitializingBean接口
afterPropertiesSet和init同时出现,前者先于后者执行,使用init方法,需要对配置文件加入init-method属性
2)bean销毁之前的行为
有两种方法:A.编写close方法 B.实现DisposableBean接口
destroy和close同时出现,前者先于后者执行,使用close方法,需要对配置文件加入destroy-method属性