1、sleep() 和 wait ()的区别

  1. 1、**sleep()**是线程类Thread 方法,**wait() **是Object 方法<br /> 2、**sleep()**让出CpuCPU可以去执行其它资源),而不会释放同步资源锁!睡眠时间到线程进入就绪状态和其他线程一起竞争cpu的执行时间。<br /> wait()让出Cpu,并且释放同步锁,未设置超时间(自动解除阻塞)只有调用notify()、notifyAll()方法唤醒,可以去参与竞争同步资源锁,进而得到执行 <br /> 3、**sleep()方法**可以在任何地方使用;**wait()方法**则只能在同步方法或同步块(synchronized块)中使用;

心得2 sleep不释放任务a资源锁,导致其它线程抢不到这个任务a,保证同步性,不需要同步块,睡眠结束自动请求执行时间, 而wait方法释放锁会出现lost wake up问题,其它线程会抢任务a,导致同步混乱,所以需要在同步方法或同步锁中执行

实例 链接一 链接二

1.1、sleep是Thread方法,wait是 Object方法

image.pngimage.png

1.2、sleep不释放锁,wait是释放锁

sleep()

  1. public class Test {
  2. private final static Object lock = new Object();
  3. public static void main(String[] args) {
  4. Stream.of("线程1","线程2").forEach(n->new Thread(n) {
  5. public void run(){
  6. Test.testSleep();
  7. }
  8. }.start());
  9. }
  10. //sleep方法休眠之后,
  11. private static void testSleep() {
  12. synchronized (lock) {
  13. try {
  14. System.out.println(Thread.currentThread().getName()
  15. +"正在执行");
  16. Thread.sleep(10_000);
  17. System.out.println(Thread.currentThread().getName()
  18. +"休眠结束");
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. }
  24. }

运行结果:
线程2先获取了cpu资源,然后开始执行休眠,在休眠过程中线程1是没法执行的,必须要等待线程2结束之后才可以。这也就是说sleep方法不会释放锁,让其他线程进来。
image.png

wait()

  1. public class Test {
  2. private final static Object lock = new Object();
  3. public static void main(String[] args) {
  4. Stream.of("线程1", "线程2").forEach(n -> new Thread(n) {
  5. public void run() {
  6. Test.testWait();
  7. }
  8. }.start());
  9. }
  10. private static void testWait() {
  11. synchronized (lock) {
  12. try {
  13. System.out.println(Thread.currentThread().getName()
  14. + "正在执行");
  15. lock.wait(10_000);
  16. System.out.println(Thread.currentThread().getName()
  17. + "wait结束");
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }
  23. }

程序结果:
image.png

1.3、sleep不依赖同步方法(synchronized),wait需要

测试sleep方法

  1. public class Test2 {
  2. private final static Object lock = new Object();
  3. public static void main(String[] args) {
  4. Stream.of("线程1", "线程2").forEach(n -> new Thread(n) {
  5. public void run() {
  6. Test2.testSleep();
  7. }
  8. }.start());
  9. }
  10. private static void testSleep() {
  11. try {
  12. Thread.sleep(10_000);
  13. System.out.println("休眠结束");
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }

这个方法会依次运行,不会出现任何异常。然后我们主要是看wait方法。

  1. public class Test2 {
  2. private final static Object lock = new Object();
  3. public static void main(String[] args) {
  4. Stream.of("线程1", "线程2").forEach(n -> new Thread(n) {
  5. public void run() {
  6. Test2.testSleep();
  7. }
  8. }.start());
  9. }
  10. private static void testWait() {
  11. try {
  12. lock.wait(10_000);
  13. System.out.println("wait结束");
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }

程序结果:
image.png

1.4、sleep不需要被唤醒,wait需要

sleep方法很简单,我们主要关注wait方法。看代码:
首先我们定义两个方法,一个等待方法,一个唤醒方法。

  1. public class Test2 {
  2. private final static Object lock = new Object();
  3. private static void testWait() {
  4. synchronized (lock) {
  5. try {
  6. System.out.println("我一直在等待");
  7. lock.wait();
  8. System.out.println("wait被唤醒了");
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. }
  14. private static void notifyWait() {
  15. synchronized (lock) {
  16. try {
  17. Thread.sleep(5_000);
  18. lock.notify();
  19. System.out.println("休眠5秒钟唤醒wait");
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }
  25. }

测试一下:

  1. public class Test2 {
  2. private final static Object lock = new Object();
  3. public static void main(String[] args) {
  4. new Thread() {//这个线程一直在等待
  5. public void run() {
  6. Test2.testWait();
  7. }
  8. }.start();
  9. new Thread() {//这个线程准备去唤醒
  10. public void run() {
  11. Test2.notifyWait();
  12. }
  13. }.start();
  14. }
  15. }

程序结果:
如果没有唤醒方法,那第一个线程就会处于一直等待的状态,第二个线程唤醒了之后就不再等待了。
image.png

2、instanceof关键字作用

instanceof 运算符是用来在运行时判断对象是否是指定类及其父类的一个实例。
比较的是对象,不能比较基本类型 即它左边的对象是否是它右边的类的实例

  1. package constxiong.interview;
  2. /**
  3. * 测试 instanceof
  4. * @author xxk
  5. * @date 2019-10-23 11:05:21
  6. */
  7. public class TestInstanceof {
  8. public static void main(String[] args) {
  9. A a = new A();
  10. AA aa = new AA();
  11. AAA aaa = new AAA();
  12. System.out.println(a instanceof A); //true
  13. System.out.println(a instanceof AA); //false
  14. System.out.println(aa instanceof AAA); //false
  15. System.out.println(aaa instanceof A); //true
  16. }
  17. }
  18. class A {
  19. }
  20. class AA extends A {
  21. }
  22. class AAA extends AA {
  23. }

3、java反射里,如果创建类的实例,请写出示例

  1. 1)通过类的对象,获取类对象
  2. Person person = new Person();
  3. Class cla = person.getClass();
  4. 场景:常用于对象的字节码获取方式
  5. 2)通过类名获取类对象
  6. Class cla = 类名.class;
  7. 场景:常用于参数的传递
  8. 3)以静态方法通过全类名获取类对象
  9. Class cla = Class.forName("全类名");
  10. 场景:常用于读取配置文件,将类名定义在配置文件中。读取文件,加载类对象。

4、通过反射获取私有属性,方法和构造方法时,该如何实现?

  1. 1.获取Class对象
  2. 1.Class userClass = User.class;
  3. 2.Class.forName(com.dsm.domain.User);
  4. 3.User user = new User();
  5. user.getClass();
  6. 2.获取所有的构造方法
  7. Constructor[] constructors = userClass.getDeclaredConstructors();
  8. //遍历构造方法
  9. Arrays.stream(constructors).forEach(System.out::println);
  10. 3.获取指定的构造方法
  11. Constructor constructor = null;
  12. try {
  13. constructor = userClass.getDeclaredConstructor(String.class);
  14. } catch (NoSuchMethodException e) {
  15. // TODO Auto-generated catch block
  16. e.printStackTrace();
  17. } catch (SecurityException e) {
  18. // TODO Auto-generated catch block
  19. e.printStackTrace();
  20. }
  21. System.out.println(constructor);
  22. 4.创建对象
  23. //开启暴力访问
  24. constructor.setAccessible(true);
  25. User user = null;
  26. try {
  27. user = (User)constructor.newInstance("董世铭");
  28. } catch (Exception e) {
  29. // TODO Auto-generated catch block
  30. e.printStackTrace();
  31. }
  32. //打印创建的对象
  33. System.out.println(user);
  34. 5.获取类的所有私有方法
  35. Method [] methods = userClass.getDeclaredMethods();
  36. Arrays.stream(methods).forEach(System.out::println);
  37. 6.获取所有的私有属性
  38. Field[] fields = userClass.getDeclaredFields();
  39. Arrays.stream(fields).forEach(System.out::println);
  40. 7.生成getset方法
  41. PropertyDescriptor pd = null;
  42. try {
  43. pd = new PropertyDescriptor(fields[0].getName(),User.class);
  44. } catch (IntrospectionException e) {
  45. // TODO Auto-generated catch block
  46. e.printStackTrace();
  47. }
  48. //生成get方法
  49. Method method = pd.getReadMethod();
  50. 8.调用方法
  51. try {
  52. System.out.println(method.invoke(user));
  53. } catch (Exception e) {
  54. e.printStackTrace();
  55. }

5、简要画一下:数组,栈,队列,链表,图,树,哈希表的数据结构

参考

6、Spring框架中都用到了哪些设计模式?并进行举例

  1. 简单工厂模式: BeanFactory ApplicationContext 创建 bean 对象。
  2. 工厂方法模式:Spring中的FactoryBean就是典型的工厂方法模式。
  3. 单例模式:Spring提供了全局的访问点BeanFactory
  4. 适配器模式:Spring中在对于AOP的处理中有Adapter模式,由于Advisor链需要的是MethodInterceptor(拦截器)对象,所以每一个Advisor中的Advice都要适配成对应的MethodInterceptor对象。
  5. 装饰模式:Spring中用到的装饰模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。
  6. 代理模式:SpringProxy模式在aop中有体现。
  7. 观察者模式:SpringObserver模式常用的地方是listener的实现。
  8. 策略模式:Spring中在实例化对象的时候用到Strategy模式。
  9. 模板方法模式:用来解决代码重复的问题。比如. RestTemplate, JdbcTemplate

7、Spring支持bean的几种作用域?

  1. singleton:单例模式,在整个Spring IoC容器中,使用 singleton 定义的 bean 只有一个实例
  2. prototype:原型模式,每次通过容器的getbean方法获取 prototype 定义的 bean 时,都产生一个新的 bean 实例
  3. request:对于每次 HTTP 请求,使用 request 定义的 bean 都将产生一个新实例,即每次 HTTP 请求将会产生不同的 bean 实例。
  4. session:同一个 Session 共享一个 bean 实例。
  5. global-session:同 session 作用域不同的是,所有的Session共享一个Bean实例。

8、Spring中的@Qualifier注解有什么作用?

@Qualifier 注解来指定应该装配哪个具体的Bean
如在控制层注入 service 而service的实现类有2个 到底使用哪个呢
image.png

9、写一个java冒泡排序算法实现

  1. public class Demo {
  2. public static void Bubble_sort(int[] list) {
  3. int length = list.length;
  4. // length 个元素,遍历 length-1 次
  5. for (int i = 0; i < length-1; i++) {
  6. // 从第 1 个元素开始遍历,遍历至 length-1-i
  7. for (int j = 0; j < length - 1 - i; j++) {
  8. // 比较 list[j] 和 list[j++] 的大小
  9. if (list[j] > list[j + 1]) {
  10. // 交换 2 个元素的位置
  11. int temp = list[j];
  12. list[j] = list[j + 1];
  13. list[j + 1] = temp;
  14. }
  15. }
  16. }
  17. }
  18. public static void main(String[] args) {
  19. int[] list = { 14, 33, 27, 35, 10 };
  20. Bubble_sort(list);
  21. // 输出已排好序的序列
  22. for (int i = 0; i < list.length; i++) {
  23. System.out.print(list[i] + " ");
  24. }
  25. }
  26. }

10、写出您所了解的会引起SQL全表扫描的情况

参考

  • 模糊查询like 全表扫描
  • 查询条件中含有is null的select语句执行慢
  • 查询条件中使用了不等于操作符(<>、!=)的select语句执行慢
  • or语句使用不当会引起全表扫描
  • select count(*) from table;这样不带任何条件的count会引起全表扫描,并且没有任何业务意义,是一定要杜绝的。

11、login_table表有id(主键)、user_id(会员id)、login_time(登录时间)三个字段,每天都有会员登录数据产生,写sql查询所有会员的最新登录时间

select user_id from login_table order by login_time desc

12、写出你所了解的提高网站并发性能 的手段

1、使用缓存 redis
2、消息队列 mq
3、数据库分库分表
4、采用集群 多服务器
5、采用分布式 再用nginx负载均衡