java面试(并发)

java线程概念,安全?

进程是系统分配资源的最小单元,线程是操作系统调度的最小单位。线程属于进程。

加锁保证安全。1.JVM提供Synchronized关键字,2.jdk提供各种lock锁

实现多线程方式?

1.继承Thread类,重写run方法:线程执行完没有返回值。本质是实现Runnable接口的一个实例。调用Thread.start()启动

2.实现Runnable接口,实现trun方法:线程执行完没有返回值。需先实例化一个Thread,并传入自己的实例。

3.使用ExecutorService,Callable,Future实现:有返回结果的多线程。执行callable会获取Future对象调用其get方法获取返回Object即可

4.使用线程池。?

ThreadPool{
	int taskSize = 5;
	ExecutorService pool = Excutors.newFixedThreadPool(taskSize);
	List<Future> list = new ArrayList<Future> {  //创建多个有返回值的任务
		for(int i = 0;i < taskSize; i++) {
			Callable c = new MyCallable(i + "");
			Future f = pool.submit(c);  //执行任务获取Future对象
			list.add(f);
		}
		poll.shutdown();
	}
}

class MyCallable implements Callable<Object> {
	private String taskName;
	MyCallable(String taskName) {
		this.taskNum = taskNum;
	}
}

Volatile和Synchronized有什么区别?Volatile能保证安全吗?DCL实现单例为什么要加Volatile?

1.volatile:保持变量的内存(线程)可见性,避免编译器优化,适用于一个线程写,一个读的场景。

synchronized:关键字,用来加锁。

2.不安全,没有原子性。

3.volatile防止指令重排(多核CPU底层指令执行顺序的优化)。在DCL中,防止高并发下指令重排造成线程安全问题。

public class singleTon{
	private static SingleTon sinaleTon = new SingleTon();  //static,启动时就创建好私有对象
	private SingleTon(){}
	public static SingleTon getSingleTon(){
		if(null == singleTon) {
			synchronized(SingleTon.class) {
				if(null == singleTon) {
					sinaleTon = new SingleTon();
				}
			}
		}
		return singleTon;
	}
}

Java线程锁机制?偏向,轻量级重量级锁区别?锁升级?

扩展maven插件:org.openjdk.jol.jol-core:把java对象在内存中的布局打印出来。

Object bean = new Object();
sout(ClassLayout.parse(bean).toPrintable());
synchornized(bean);
sout(ClassLayout.parse(bean).toPrintable());

1.java锁:可看出加锁只是在对象头部markword上做一个锁状态标记。无锁,偏向锁,轻重量级锁对应不同锁状态。
锁标志
2.java锁机制:就是根据资源竞争程度不断进行锁升级的过程。
扩展jvm底层参数:-XX:UsedBiasedLocking:是否打开偏向锁,默认不打开 -XX:BiasedLockingStartupDelay:默认4s,打开
锁升级

AQS理解,AQS怎么实现可重入锁?

1.AQS是java线程同步的框架,是jdk中很多锁的核心实现框架。AQS中维护了一个信号量state和一个线程组成的双向链表队列。state用来控制线程排队或放行。
2.在可重入锁的场景下,state就用来表示加锁的次数。0表示无锁,加一次锁state+1,释放-1。
例子:手写一个MyReentrantLock。
aqs

有A,B,C三个线程,如何保证三线程同步执行?并发下依次执行?有序交错执行?

主要考三个并发工具:CountDownLatch(倒数同步栅栏),CylicBarrier(计数同步栅栏),Semaphore(满足信号量<个数>后执行)。

1.线程同步执行
int size = 3;
CountDownLatch count = new CountDownLatch();
for(int i = 0; i < size; i++) {  //可模拟高并发场景
	new Thread(() -> {
		count.await();  //所有线程排队,等待主线程倒数
	}).start();
}
Thread,sleep(5000);  //线程准备
count.countDown();
2.线程依次执行
static volatile int sem = 1;  //信号量,加volatile为了让其他线程感知到sem变化
Thread t1 = new Thread(() -> {while(true){if(sem==1) sout(a); sem = 2; return;}});
Thread t2 = new Thread(() -> {while(true){if(sem==2) sout(a); sem = 3; return;}});
Thread t3 = new Thread(() -> {while(true){if(sem==3) sout(a); sem = 1; return;}});
3.交错执行
private static Semaphore s1 = new Semaphore(1);
private static Semaphore s2 = new Semaphore(1);
private static Semaphore s3 = new Semaphore(1);
s1.acquire();
s2.acquire();
new Thread(() -> {while(true){s1.acquire(); sout("A"); s2.release();}}).start();
new Thread(() -> {while(true){s2.acquire(); sout("B"); s3.release();}}).start();
new Thread(() -> {while(true){s3.acquire(); sout("C"); s1.release();}}).start();

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

思路:fork/join框架,实例:https://blog.youkuaiyun.com/qq_40100414/article/details/119202893 ; https://blog.youkuaiyun.com/u011294519/article/details/88368142
分治

private static int inits[] = new int[100];
Random r = new Random();
for(int index = 1;index < 100; index++) {
	inits[index - 1] = r,nextInt(1000);
}

ForkJoinPool pool = new ForkJoinPool();
MyTask task = new MyTask(inits);
ForkJoinTask<int[]> taskResult = pool.submit(task);
int[] ints = taskResult.get();
sout(Arrays.toString(ints));

class MyTask extends RecursiveTask<int[]> {
	private int source[];
	protected int[] compute() {
		int sourceLen = source.length;
		if(sourceLen > 2) {  //如果数组长度大于2,说明任务中要进行排序的集合还不够小
			int midIndex = sourceLen / 2;
			//拆分成2个任务
			MyTask task1 = new MyTask(Arrays.copyOf(source, midIndex));
			task1.fork();
			MyTask task2 = new MyTask(Arrays.copyOfOfRange(source, midIndex, sourceLen));
			task2.fork();
			//将2个有序的数组,合并成一个有序数组
			int result1[] task1.join();
			int result2[] task2.join();
			int mer[] joinInts(result,result2);
			return mer;
		} else {  //拆分剩1,2个了开始合并
			if(sourceLen == 1 || source[0] <= source[1]) {  //只有一个元素
				return source;
			} else {
				int targetp[] = new int[sourthlen];
				targetp[0] = source[1];
			}
		}
	}
}
int[] joinInts(int arr1[], int arr2[]) {
	int destInts[] new int[arr1.length + arr2.length];
	int array1Len = array1.length;
	int array2Len = array2.length;
	int destLen = destInts.length;
    // 只需要以新的集合destInts的长度为标准,遍历一次即可
    for (int index = 0, array1Index = 0, array2Index = 0; index < destLen; index++) {
        int value1 = array1Index >= array1Len ? Integer.MAX_VALUE : array1[array1Index];
        int value2 = array2Index >= array2Len ? Integer.MAX_VALUE : array2[array2Index];
        // 如果条件成立,说明应该取数组array1中的值
        if (value1 < value2) {
            array1Index++;
            destInts[index] = value1;
        }
        // 否则取数组array2中的值
        else {
            array2Index++;
            destInts[index] = value2;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值