Java面试习题

Java面试习题,第1张

Java面试习题 JavaSE面试题 1. 自增变量

给出最后 i、j、k 的值

 public static void main(String[] args) {
        int i = 1;
        i = i++;
        int j = i++;
        int k = i + ++i * i++;
        System.out.println("i=" + i);
        System.out.println("j=" + j);
        System.out.println("k=" + k);
    }

结果: i = 4, j = 1, k = 11;
过程如下:
小结:

  • 赋值 *** 作=最后计算,将 *** 作数栈赋值到局部变量表;
  • =右侧元素从左到右加载值依次压入 *** 作数栈;
  • *** 作数栈中的运算要依照运算符优先级;
  • 自增、自减 *** 作直接在局部变量表中改变变量的值,不经过 *** 作数栈;
  • 最后的赋值之前,临时结果也存储在 *** 作数栈中。
2. 单例模式 Singleton Pattern

单例模式是Java中最简单的设计模式之一,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注:

  1. 单例类只能有一个实例:构造器私有化;
  2. 单例类必须自己创建自己的唯一实例:含有一个该类的静态变量来保存这个唯一的实例。
  3. 单例类必须给所有其他对象提供这一实例:对外提供获取该实例对象:(1)直接暴露;(2)用静态变量的get方法获取;

几种常见形式:
饿汉式 ,直接创建对象,不存在线程安全问题,具体分为:

  • 直接实例化饿汉式(简洁直观)
  • 枚举式(最简洁)
  • 静态代码块饿汉式(适合复杂实例化)

懒汉式, 延迟创建对象,具体分为:

  • 线程不安全(适用于单线程)
  • 线程安全(适用于多线程)
  • 静态内部类形式(适用于多线程)
多线程 CAS(compare and swap, compare and exchange)

保证在没有锁的状态下,多线程下保持一一致性实现值的改变。

ABA问题:分手,找别人,复合;中间的经历无法感知。
AtomicInteger

JUC

JUC是java.util.concurrent工具包的简称,这是一个处理线程的工具包,从JDK1.5开始出现。

进程与线程

进程Process:是系统进行资源分配和调度的基本单位,是 *** 作系统结构的技术。进程是线程的容器,程序是指令、数据及组织形式的描述,进程是程序的实体。
线程Thread:是 *** 作系统能够进行运算掉的最小单位,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

线程的状态

线程状态枚举类

public enum State {
	NEW,(新建)
	RUNNABLE,(准备就绪),
	BLOCKED,(阻塞)
	WAITING,(等待:不见不散,约个人五点到,五点不到会继续等)
	TIMED_WAITING,(等待:过时不候,约定时间未到直接走人)
	TERMINATED;(终结)
}
wait,sleep区别
  1. sleep()是Thread的静态方法;wait()是Object的方法,任何对象实例都能调用。
  2. sleep()执行时不会释放锁,也不需要占用锁;wait会释放锁,但是调用的前提是当前线程占有锁(即代码要在synchronized中)。
  3. 都可以被interrupted()方法中断,都是在哪里睡哪里醒。
管程

管程即为Monitor监视器,保证了同一时刻只有一个进程在管程内活动,即管程内定义的 *** 作在同一时刻只能被一个线程访问被保护的数据或代码。
JVM同步基于进入加锁和退出解锁,使用管程对象实现的,每个Java对象都一个管程对象,随着java对象一同创建和销毁。

用户线程、守护线程

用户线程:平时用到的普通线程,如自定义线程。当主线程结束后,用户线程还在运行,JVM存活。
守护线程:运行在后台的特殊线程,比如垃圾回收。如果没有用户线程了,只剩下守护线程,jvm结束。守护线程的设置setDaemon(true)要在线程运行之前。

Synchronized

synchronized是Java中的关键字,是一种同步锁,它修饰的对象有以下几种:

  1. 修饰一个代码块,作用的对象是对用这个代码块的对象;
synchronized(this){
	//修饰的是大括号中的代码
}
  1. 修饰一个方法,被修饰的方法称为同步方法,其作用范围是整个方法,作用对象是调用这个方法的对象。
  2. 修饰一个静态方法,作用范围是整个静态方法,作用的对象是这个类的所有对象。
  3. 修饰一个类;

多线程编程步骤:

  1. 创建资源类,在资源类创建属性和 *** 作方法(高内聚,低耦合:资源有什么就调用什么,没有就不调用)。
  2. 创建多个线程,调用资源类的 *** 作方法。

通过synchronized实现一个卖票实例,3个售票员卖出30张票,票类Ticket有属性number记录票数目,方法sale()进行卖票并且通过synchronized加锁,

package com.jiayuleng.jucstudy.sync;

class Ticket {
//    票数
    private int number = 30;
//     *** 作方法:买票
    public synchronized void sale() {
//        判断:是否有票;
        if(number > 0) {
            System.out.println(Thread.currentThread().getName() + ": 卖出:" + (number--) + " 剩下:" + number);
        }
    }

}

public class SaleTicket {
//    第二步 创建多个线程,调用资源类的 *** 作方法
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0; i < 40; i++) {
                    ticket.sale();
                }
            }
        }, "AA").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0; i < 40; i++) {
                    ticket.sale();
                }
            }
        }, "bb").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0; i < 40; i++) {
                    ticket.sale();
                }
            }
        }, "cc").start();
    }
}

如果不加锁,会出现线程不同步的情况。

多线程的创建 一、继承于Thread类
  1. 创建一个继承于Thread类的子类。
  2. 重写Thread类的run()方法,将此线程执行的 *** 作声明在run()中。
  3. 创建Thread类的子类的对象。
  4. 通过此类调用start()方法。

例,通过子线程输出[0, 100)的偶数

package com.jiayuleng.javabasestudy.threadstudy.threadcreate;
//        1.创建一个继承于Thread类的子类。
//        2.重写Thread类的run()方法,将此线程执行的 *** 作声明在run()中。
//        3.创建Thread类的子类的对象。
//        4.通过此类调用start()方法。

//例子:遍历100以内的所有的偶数


class MyThread extends Thread {
    @Override
    public void run() {
        for(int i = 0; i < 100; i++) {
            if(i % 2 == 0) {
                System.out.println(i);
            }
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
        for(int i = 0; i < 100; i++) {
            if(i % 2 == 0) {
                System.out.println(i + "******main*******");
            }
        }
    }
}

主线程与子线程交替运行如下图

问题一:我们不能通过直接调用run()的方式启动线程,start()方法会先启动当前线程,再调用当前线程的run()方法。
问题二:同一个线程对象不可以启动start()方法两次,会报IllegalThreadStateException异常;

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4874246.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-11
下一篇 2022-11-11

发表评论

登录后才能评论

评论列表(0条)

保存