JAVA基础相关面试题--05

@线程同步?
同步就是协同步调,按预定的先后次序进行运行。线程同步是指多线程通过特定的设置)—如互斥量、实践对象、临界区)来控制线程之间的执行顺序。也可以说是在线程之间通过同步建立起执行顺序的关系。如果没有同步,那线程之间是各自运行各自的。

线程互斥是指对共享的进程系统资源在各单个线程访问时的排他性。当有若干个先后才能都要使用某一个共享资源时,任何时刻最多只允许一个线程去使用,其他要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步。

@线程的通信机制?(wait-notify机制)
实现多个线程之间的通信可以使用wait、notify、notifyAll三个方法。这三个方法都是Object类的方法。
wait():当值当前线程等待,直到另一个线程调用此对象的notify()方法或notifyAll()方法。
wait(long timeout):当值当前线程等待,直到另一个线程调用此对象的notify()方法或notifyAll()方法,或者已经过了指定的时间量。
notify():唤醒正在此对象监视器上等待的单个线程。
notifyAll():唤醒等待此对象监视器的所有线程。
在调用以上方法时必须获得对象的对像素,要在同步方法,或者同步块中调用,否则会被抛出异常IllegaIMonitorStateException.wait执行后锁被自动释放,notify执行后并不会立即释放此对象的锁,需要等到notify的synchronize方法执行完全后,wait的线程才能获得对象锁。

public class ThreadWait extends Thread {
    private Object work;
 
    public ThreadWait(Object work) {
        this.work = work;
    }
 
    @Override
    public void run() {
        try {
            synchronized (work){
                System.out.println("...before wait...");
                work.wait();
                System.out.println("...after wait...");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class ThreadNotify extends Thread {
    private Object work;
 
    public ThreadNotify(Object work) {
        this.work = work;
    }
 
    @Override
    public void run() {
        synchronized (work){
            System.out.println("...before notify...");
            work.notify();
            System.out.println("...after notify...");
            //此处可测试,notify执行后并没有释放此对象的锁,需要等到notify的synchronized方法执行完全后,wait的线程才能获得对象锁。
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("...after notify synchronized...");
    }
}
public class WaitNotifyTest {
    public static void main(String[] args) {
        Object work = new Object();
        ThreadWait wait = new ThreadWait(work);
        wait.start();
        ThreadNotify notify = new ThreadNotify(work);
        notify.start();
    }
}
//结果:
...before wait...
...before notify...
...after notify...
...after notify synchronized...
...after wait...

@扩展:ConcurrentHashMap如何实现多并发的?CAS无锁化解决多线程并发:【乐观锁
、Synchronize关键字解决多线程并发【悲观锁】
JDK1.7版本的ConcurrentHashMap实现原理
在JDK1.7中采用了数组+segment(分段锁)+HashEntry的方式实现
Segment:分段锁类似于HashMap的结构,即内部拥有一个Entry数组,数组中 每个元素又是一个列联表,同时又是一个ReentrantLock(重入锁,Segment继承了ReentrantLock)
ConcurrentHashMap使用分段锁技术,将数据分成一段一段的存储,然后给每一段数据配一把所,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问,能够实现真正的并发访问。ConcurrentHashMap定位一个元素的过程需要进行两次Hash操作,第一次Hash定位到Segment,第二次Hash定位到元素所在的链表的头部。
优点:写操作的时候可以只对元素所在的Segment进行加锁即可,不会影响到其他的Segment。
缺点:Hash的过程要比普通的HashMap时间要长。

JDK1.8版本的ConcurrentHashMap实现原理
JDK8中ConcurrentHashMap参考了JDK8 HashMap的实现,采用了CAS+synchronize控制并发操作,数组+链表+红黑树进行存储的方式,内部大量采用CAS操作。JDK8中采用Node思想。
Node:保存key,value以及key的hash值的数据结构。其中value和next都是用volatile修饰,保证并发的可见性。
https://www.cnblogs.com/jiarui-zjb/p/9596150.html
CAS是compare and swap的缩写,即我们所说的比较交换。CAS是一种基于锁的操作,而且是乐观锁。在java中锁被分为乐观锁和悲观锁。
CAS操作包含三个操作数----内存位置(V)、预期原值(A)和新值(B)。如果内存地址里面的值和A的值是一样的,那么将内存里的值更新成B。CAS是通过无线循环来获取数据的,如果在第一轮循环中,a线程获取地址里面的值被b线程修改了,那么a线程需要自旋,到下次循环才有可能有机会执行。

@什么是乐观锁?什么是悲观锁?
悲观锁:
是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。
当我我们要对一个数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对改数据进行加锁以防止并发。这种借助数据库锁机制,在修改数据之前先锁定,在修改的当时称之为悲观并发控制。
乐观锁:
采取了一种宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加version来获取数据,性能较悲观锁有很大的提高。
乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。

@如何获取一个类的描述类Class类的实例对象?(至少有三种方式)
1. 运用.class的方式来获取Class实例,对于基本数据类型的封装类,还可以采用.TYPE来获取相应的基本类型。Integer.TYPE 或 int.class 或类名.class
2. 利用对象调用getClass()方法获取改对象的Class实例。
3. 使用Class类的静态方法 forName(),用类的名字获取一个class实例,这种方式的灵活性最高,根据类的字符串全名即可获取class实例,可以动态加载类,框架设计经常会用到。

=================================================================

JDBC连接数据库
1.加载数据库驱动
2.建立数据库连接
3.获取数据库的SQL语句的执行器对象
4.获取数据库连接的执行器执行SQL语句的结果集
5.解析SQL执行之后的结果集

注意MySQL5和MySQL8两个版本的连接串的写法不同,且驱动jar包也不同,使用时注意区分

@JDBC是如何加载数据库驱动的?JDBC是如何初始化数据库驱动的?都有哪些方式?
JDBC加载数据库驱动:
一个java引用程序要想和数据库连接起来,则需要调用JDBC接口,那么第一步要做的就是把驱动程序加载进系统内存,供系统使用。当我们在使用class.forName()加载Oracle的驱动oracle.jdbc.driver.OracleDriver时,会执行OracleDriver中的静态代码段,创建一个OracleDriver实例,然后调用DriverManager.registerDriver()注册,之后可以利用DriverManager获取连接,从而进行java和数据库之间的对话。
JDBC初始化数据库驱动:

	public static Connection conn = null;
    public static PreparedStatement pstmt = null;
    public static ResultSet rs = null;

    private static String className = "com.mysql.jdbc.Driver";
    private static String url = "jdbc:mysql://localhost:3306/person_management";
    private static String dbName = "root";
    private static String dbPassword = "199703";

    public static Connection getConn(){

        try {
			//加载驱动程序
            Class.forName(className);

			//获取数据库连接
            conn = DriverManager.getConnection(url, dbName, dbPassword);

        }catch (Exception e){
            e.printStackTrace();
        }

        return conn;
    }

加载JDBC驱动程序的方法:
Class.forName( “com.mysql.jdbc.Driver” );
DriverManager.registerDriver( new com.mysql.jdbc.Driver() );
System.setProperty( “jdbc.driver” , “com.mysql.jdbc.Driver” )

@try-catch 在1.7下的with方式的资源回收?
【提示:try(回收资源声明初始化语句及){ } catch(Exception e ){ }】

这是jdk1.7加入的try-with-resources写法,可以用来代替之前的try-catch-finally语句块,实现对某些资源开销大的resource省去写finally语句块释放资源的代码,例如关闭流、断开数据库连接等等,都不在需要写finally语句块释放资源,try-with-resources会自动释放try后面()内占用的资源。
try-with-catch语句是一个声明一个或多个资源的try语句。一个资源作为一个对象,必须在程序结束之后关闭,try-with-resources语句确保在语句的最后每个资源都被关闭,任何实现了java.lang.AutoCloseable和java.io.Closeable的对象都可以使用try-with-resource来实现异常处理和资源关闭。
jdk1.7之前我们必须在finally块中手动关闭资源,否则会导致资源的泄露
jdk1.7之后就可以使用try-with-resource,不需要我们在finally块中手动关闭资源。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值