其他分享
首页 > 其他分享> > 面试题突击(一)

面试题突击(一)

作者:互联网

Java如何开启线程?怎么保证线程安全?

进程是系统资源调度的最小单位,线程是系统任务调度的最小单位。一个进程可以有多个线程,线程共享进程内的资源。

开启线程的方式:

  1. 继承Thread,重写run()方法
public class ThreadTest {
    public class MyThread extends Thread{
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程执行完毕");
        }

    }

    public static void main(String[] args) {
        MyThread t = new ThreadTest().new MyThread();
        t.start();
        System.out.println("父线程执行完毕");
    }
}

2.实现Runnable接口,重写run()方法

public class ThreadTest {
    public class MyRunnable implements Runnable{
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程执行完毕");
        }

    }

    public static void main(String[] args) {
        Thread t = new Thread(new ThreadTest().new MyRunnable());
        t.start();
        System.out.println("父线程执行完毕");
    }
}

3.实现Callable重写call()方法
借助Thread:

public class ThreadTest {
    public class MyCallable implements Callable<Integer> {


        @Override
        public Integer call() throws Exception {
            int num = new Random().nextInt(5);
            Thread.sleep(num*1000);
            System.out.println("子线程执行完毕"+num);
            return num;
        }
    }

    public static void main(String[] args) {
        FutureTask futureTask = new FutureTask(new ThreadTest().new MyCallable());
        Thread t = new Thread(futureTask);
        t.start();
        System.out.println("父线程执行完毕");
        try {
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

线程池方式:

public class ThreadTest {
    public class MyCallable implements Callable<Integer> {


        @Override
        public Integer call() throws Exception {
            int num = new Random().nextInt(5);
            Thread.sleep(num*1000);
            System.out.println("子线程执行完毕"+num);
            return num;
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<Integer> future = executorService.submit(new ThreadTest().new MyCallable());
        System.out.println("父线程执行完毕");
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

扩展,公平锁非公平锁

公平锁:按照线程申请锁的顺序,依次放入队列中,永远是排在第一位的线程获得锁
优点:不会有线程饿死,所有线程最终都会获得锁
缺点:降低了吞吐量,除了排在第一位的线程,其他线程都会阻塞,对CPU的开销比较大

非公平锁:需要获得锁的线程,先尝试获得锁,若未获得锁再进入队列中
优点:增加了吞吐量,CPU不必唤醒所有线程,减少系统开销
缺点:因为非公平,可能存在队列当中有线程饿死的情况

扩展,乐观锁和悲观锁

悲观锁:利用数据库的锁机制,修改前先对数据进行锁定的方式,叫做悲观锁

volatile和synchronized区别?volatile能不能保证线程安全?DCL单例问什么要加volatile?

volatile是用来保证不同线程之间可见性,synchronized是用来加锁的,volatile适用用一个线程写,多个线程读的场景。

volatile只能保证线程之间的可见性,不是原子操作,是线程不安全的。

volatile能防止指令重排,防止在多线程情况下,因指令重排造成的线程不安全的情况。

Java线程锁机制是怎样的?偏向锁,轻量级锁,重量级锁有什么区别?锁机制是如何升级的?

下图来自图灵《金三银四为大家整理了68道高频java面试题,花点耐心看完,offer拿到手软!》
在这里插入图片描述

谈谈对AQS的理解?AQS是如何实现可重入锁的?

AQS是java线程同步框架,是java很多锁机制的核心。

  1. 有个信号量,相当于红绿灯,控制线程的流转
  2. 有个双向链表,里面维护着头节点和尾节点

可重入锁场景下,state=0表示无锁,加一次锁就加一,释放一次就减一

ABC三个线程如何保证同时执行?如何保证依次执行?如何保证有序交错执行?

countDownLatch.await();countDownLatch.countDown();
后面两个其实用个信号量可以了。

扩展,CountDownLatch,CylicBarrier,Semaphere

如何对一个字符串快速排序?

Fork/Join框架:

public class ForkJoinCalculator implements Calculator{
    ForkJoinPool pool;
    public ForkJoinCalculator(){
        pool = new ForkJoinPool();
    }

    private static class MyTask extends RecursiveTask<int[]>{
        int[] nums;
        int start;
        int end;
        public MyTask(int[] nums, int start, int end){
            this.nums = nums;
            this.start = start;
            this.end = end;
        }
        @Override
        protected int[] compute() {
            if(start == end){
                return nums;
            }else{
                int mid = (start+end)/2;
                MyTask t1 = new MyTask(nums,start,mid);
                MyTask t2 = new MyTask(nums,mid+1,end);
                t1.fork();
                t2.fork();
                int []r1 = t1.join();
                int []r2 = t2.join();
                int[] tmp = new int[end-start+1];
                int i1 = start;
                int i2 = mid+1;
                int ii = 0;
                while(i1 <= mid && i2 <= end){
                    if(r1[i1]<r2[i2]){
                        tmp[ii++]=r1[i1++];
                    }else{
                        tmp[ii++]=r2[i2++];
                    }
                }

                while(i1 <= mid)
                    tmp[ii++]=r1[i1++];
                while(i2 <= end)
                    tmp[ii++]=r2[i2++];

                for(int i = 0; i < tmp.length; i++){
                    nums[i+start]=tmp[i];
                }
                return nums;
            }
        }
    }
    @Override
    public int[] sort(int[] numbers) {
        int[] res = pool.invoke(new MyTask(numbers,0,numbers.length-1));
        pool.shutdown();
        return res;
    }
}
public class Main {
    public static void main(String[] args){
        Main solution = new Main();
        int[] its = new int[10000];
        Random random = new Random();
        for(int i = 0; i < 10000; i++){
            its[i] = random.nextInt(1000);
        }
        int[] items = new ForkJoinCalculator().sort(its);
        for(int item:items){
            System.out.print(item+" ");
        }
        System.out.println();
    }
}
public interface Calculator {
    int[]  sort(int[] numbers);
}

标签:面试题,int,System,start,线程,new,突击,public
来源: https://blog.csdn.net/yu_duan_hun/article/details/116399847