面试题突击(一)
作者:互联网
Java如何开启线程?怎么保证线程安全?
进程是系统资源调度的最小单位,线程是系统任务调度的最小单位。一个进程可以有多个线程,线程共享进程内的资源。
开启线程的方式:
- 继承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很多锁机制的核心。
- 有个信号量,相当于红绿灯,控制线程的流转
- 有个双向链表,里面维护着头节点和尾节点
可重入锁场景下,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