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。
有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.csdn.net/qq_40100414/article/details/119202893 ; https://blog.csdn.net/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;
}
}
}