int short long byte boolean float double char
可重入锁:指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的。也就是说同一个线程再次调用lock的时候,可以继续执行lock后面的方法。
synchronized和ReentrantLock都是可重入锁。可重入锁的意义之一在于防止死锁。
实现原理实现是通过为每个锁关联一个请求计数器和一个占有它的线程。
当计数为0时,认为锁是未被占有的;
线程请求一个未被占有的锁时,JVM将记录锁的占有者,并且将请求计数器置为1 。
如果同一个线程再次请求这个锁,计数器将递增;每次占用线程退出同步块,计数器值将递减。直到计数器为0,锁被释放。
关于父类和子类的锁的重入:子类覆写了父类的synchonized方法,然后调用父类中的方法,此时如果没有可重入的锁,那么这段代码将产生死锁
悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁.这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁.但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。
乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。
在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
- 如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)
- 对于多列索引,不是使用的第一部分(第一个),则不会使用索引
- like查询是以%开头
- 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
- 如果mysql估计使用全表扫描要比使用索引快,则不使用索引
- 没有查询条件,或者查询条件没有建立索引
- 在查询条件上没有使用引导列
- 查询的数量是大表的大部分,应该是30%以上。
- 索引本身失效
- 查询条件使用函数在索引列上,或者对索引列进行运算(+,-,*,/,! 等) 错误的例子:select * from test where id-1=9; 正确的例子:select * from test where id=10;
- 对小表查询
- 提示不使用索引
- 统计数据不真实
- CBO计算走索引花费过大的情况。其实也包含了上面的情况,这里指的是表占有的block要比索引小。
- 隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误. 由于表的字段tu_mdn定义为varchar2(20),但在查询时把该字段作为number类型以where条件传给Oracle,这样会导致索引失效. 错误的例子:select * from test where tu_mdn=13333333333; 正确的例子:select * from test where tu_mdn='13333333333';
- 1,<> 2,单独的>,<,(有时会用到,有时不会)
- like "%_" 百分号在前.
- 表没分析.
- 单独引用复合索引里非第一位置的索引列.
- 字符型字段为数字时在where条件里不添加引号.
- 对索引列进行运算.需要建立函数索引.
- not in ,not exist.
- 当变量采用的是times变量,而表的字段采用的是date变量时.或相反情况。
- B-tree索引 is null不会走,is not null会走,位图索引 is null,is not null 都会走
- 联合索引 is not null 只要在建立的索引列(不分先后)都会走, in null时 必须要和建立索引第一列一起使用,当建立索引第一位置条件是is null 时,其他建立索引的列可以是is null(但必须在所有列 都满足is null的时候),或者=一个值; 当建立索引的第一位置是=一个值时,其他索引列可以是任何情况(包括is null =一个值),以上两种情况索引都会走。其他情况不会走。
normal:表示普通索引
unique:表示唯一的,不允许重复的索引,如果该字段信息保证不会重复例如身份证号用作索引时,可设置为unique
full textl: 表示 全文搜索的索引。 FULLTEXT 用于搜索很长一篇文章的时候,效果最好。用在比较短的文本,如果就一两行字的,普通的 INDEX 也可以。总结,索引的类别由建立索引的字段内容特性来决定,通常normal最常见。
TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 1. IA 接口类中的getName()方法只是示例
* 2. 实现checkName方法,要求:
* 1. 当IA方法名等于 “&” 后的值的时候,输出 “=” 后的值
* 2. 否则输出 null
* 3. IA 接口类和 main 方法已实现
* 考点:
* 1. 使用代理模式实现具体的方法逻辑
*/
public class ShowMeBug {
public interface IA{
String getName();
}
public static void main(String[] args) {
IA ia = (IA) checkName(IA.class.getName() + "&getName=Abc");
System.out.println(ia.getName());
IA ia2 = (IA) checkName(IA.class.getName() + "&getTest=ers");
System.out.println(ia2.getName());
}
//需要实现的具体逻辑
private static Object checkName(String str){
String[] split = str.split("&", -1);
String[] strings = split[1].split("=", -1);
String check = strings[0];
String result = strings[1];
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals(check)){
return result;
}
return null;
}
};
return Proxy.newProxyInstance(IA.class.getClassLoader(), new Class[]{ IA.class }, invocationHandler);
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 同时100个线程一起存钱,每次存1块钱
* 1. 实现 deposit() 存钱方法
* 2. 在 main() 中实现具体逻辑
* 考点:
* 1. 主线程和子线程之间的控制问题
* 2. 反射方式获取方法执行(加分项)
* 3. 线程池控制精细化控制子线程执行情况(加分项)
*/
public class ShowMeBug {
private static final Logger LOGGER = LoggerFactory.getLogger(ShowMeBug.class);
private double balance;
public void deposit(double money){
//实现具体的存钱逻辑
synchronized (this){
double nowBalance = getBalance();
balance = nowBalance + money;
LOGGER.warn("ID: " + String.valueOf(Thread.currentThread().getId())+" >>>>>> NAME: " + Thread.currentThread().getName());
}
}
private double getBalance() {
// 获取余额
return balance;
}
public static void main(String[] args) {
try {
final Class<ShowMeBug> showMeBugClass = ShowMeBug.class;
Object newInstance = showMeBugClass.newInstance();
BlockingQueue<Runnable> blockingQueue = new LinkedBlockingDeque<>(10);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(20, 100, 60, TimeUnit.SECONDS, blockingQueue);
threadPoolExecutor.prestartAllCoreThreads();
for (int i = 0; i < 100; i++) {
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
try {
Method deposit = showMeBugClass.getMethod("deposit", double.class);
deposit.invoke(newInstance, 1);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
threadPoolExecutor.shutdown();
threadPoolExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
System.out.println(showMeBugClass.getDeclaredField("balance").get(newInstance));
} catch (Exception e) {
e.printStackTrace();
}
}
}
import java.math.BigDecimal;
import java.text.DecimalFormat;
/**
* 保留 a/b 计算结果小数点后一位
* 考点:
* 1. 这题主要考虑到 double 精度问题导致计算显示不正确
*/
public class ShowMeBug {
public static void main(String[] args) {
double a = 3;
double b = 2222222222222222222222.0;
double i = a / b;
//计算结果为科学计数法表示
System.out.println(i);
//精度不足,超过一定位数后直接以0补全
DecimalFormat decimalFormat = new DecimalFormat("0.00000000000000000000000000000000000000000000000000000000000000");
System.out.println(decimalFormat.format(i));
//使用 BigDecimal 计算
BigDecimal bigDecimal = new BigDecimal(i);
String plainString = bigDecimal.toPlainString();
System.out.println(plainString);
//精度不足,保留小数点后位数不多的可以使用
String format = String.format("%.45f", Double.valueOf(plainString));
System.out.println(format);
//精度足够,但是不能四舍五入,需要单独处理
System.out.println(plainString.substring(0, 45));
}
}