赞
踩
来自黑马程序员(新版Java面试专题视频教程,java八股文面试全套真题+深度详解(含大厂高频面试真题)_哔哩哔哩_bilibili)
目录
1.7 新建 T1、T2、T3 三个线程,如何保证它们按顺序执行?
1.8 notify()和 notifyAll()有什么区别?
1.9 在 java 中 wait 和 sleep 方法的不同?
4.1 线程池使用场景CountDownLatch、Future(你们项目哪里用到了多线程)
难易程度:☆☆出现频率:☆☆☆
难易程度:☆出现频率:☆
举例:
- 家庭主妇做饭、打扫卫生、给孩子喂奶,她一个人轮流交替做这多件事,这时就是并发
- 家庭主妇雇了个保姆,她们一起这些事,这时既有并发,也有并行(这时会产生竞争,例如锅只有一口,一个人用锅时,另一个人就得等待)
- 雇了3个保姆,一个专做饭、一个专打扫卫生、一个专喂奶,互不干扰,这时是并行
难易程度:☆☆出现频率:☆☆☆☆
- public class MyThread extends Thread {
- @Override
- public void run() {
- System.out.println("MyThread...run...");
- }
- public static void main(String[] args) {
- // 创建MyThread对象
- MyThread t1 = new MyThread() ;
- MyThread t2 = new MyThread() ;
- // 调用start方法启动线程t1.start();
- t2.start();
- }
- }
- public class MyRunnable implements Runnable{
- @Override
- public void run() {
- System.out.println("MyRunnable...run...");
- }
- public static void main(String[] args) {
- // 创建MyRunnable对象
- MyRunnable mr = new MyRunnable() ;
- // 创建Thread对象
- Thread t1 = new Thread(mr) ;
- Thread t2 = new Thread(mr) ;
- // 调用start方法启动线程
- t1.start();
- t2.start();
- }
- }

- public class MyCallable implements Callable<String> {
- @Override
- public String call() throws Exception {
- System.out.println("MyCallable...call...");
- return "OK";
- }
- public static void main(String[] args) throws ExecutionException, InterruptedException{
- // 创建MyCallable对象
- MyCallable mc = new MyCallable() ;
- // 创建F
- FutureTask<String> ft = new FutureTask<String>(mc) ;
- // 创建Thread对象
- Thread t1 = new Thread(ft) ;
- Thread t2 = new Thread(ft) ;
- // 调用start方法启动线程
- t1.start();
- // 调用ft的get方法获取执行结果
- String result = ft.get();
- // 输出
- System.out.println(result);
- }
- }

- public class MyExecutors implements Runnable{
- @Override
- public void run() {
- System.out.println("MyRunnable...run...");
- }
- public static void main(String[] args) {
- // 创建线程池对象
- ExecutorService threadPool =
- Executors.newFixedThreadPool(3);
- threadPool.submit(new MyExecutors()) ;
- // 关闭线程池
- threadPool.shutdown();
- }
- }
难易程度:☆☆出现频率:☆☆☆
难易程度:☆☆出现频率:☆☆
难易程度:☆☆☆出现频率:☆☆☆☆
- public enum State {
- /**
- * 尚未启动的线程的线程状态
- */
- NEW,
- /**
- * 可运行线程的线程状态。处于可运行状态的线程正在 Java 虚拟机中执行,但它可能正在等待来自 * 操作系统的其他资源,例如处理器。
- */
- RUNNABLE,
- /**
- * 线程阻塞等待监视器锁的线程状态。处于阻塞状态的线程正在等待监视器锁进入同步块/方法或在调 * 用Object.wait后重新进入同步块/方法。
- */
- BLOCKED,
- /**
- * 等待线程的线程状态。由于调用以下方法之一,线程处于等待状态:
- * Object.wait没有超时
- * 没有超时的Thread.join
- * LockSupport.park
- * 处于等待状态的线程正在等待另一个线程执行特定操作。
- * 例如,一个对对象调用Object.wait()的线程正在等待另一个线程对该对象调用Object.notify() * 或Object.notifyAll() 。已调用Thread.join()的线程正在等待指定线程终止。
- */
- WAITING,
- /*** 具有指定等待时间的等待线程的线程状态。由于以指定的正等待时间调用以下方法之一,线程处于定 * 时等待状态:
- * Thread.sleep
- * Object.wait超时
- * Thread.join超时
- * LockSupport.parkNanos
- * LockSupport.parkUntil
- * </ul>
- */
- TIMED_WAITING,
- /**
- * 已终止线程的线程状态。线程已完成执行
- */
- TERMINATED;
- }

状态之间是如何变化的
难易程度:☆☆出现频率:☆☆☆
- public class JoinTest {
- public static void main(String[] args) {
- // 创建线程对象
- Thread t1 = new Thread(() -> {
- System.out.println("t1");
- }) ;
- Thread t2 = new Thread(() -> {
- try {
- t1.join(); // 加入线程t1,只有t1线程执行完毕以后,再次执行该线程
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("t2");
- }) ;
- Thread t3 = new Thread(() -> {
- try {
- t2.join(); // 加入线程t2,只有t2线程执行完毕以后,再次执行该线程
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("t3");
- }) ;
- // 启动线程
- t1.start();
- t2.start();
- t3.start();
- }
- }

- package com.itheima.basic;
- public class WaitNotify {
- static boolean flag = false;
- static Object lock = new Object();
- public static void main(String[] args) {
- Thread t1 = new Thread(() -> {
- synchronized (lock){
- while (!flag){System.out.println(Thread.currentThread().getName()+"...wating...");
- try {
- lock.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- System.out.println(Thread.currentThread().getName()+"...flag is true");
- }
- });
- Thread t2 = new Thread(() -> {
- synchronized (lock){
- while (!flag){
- System.out.println(Thread.currentThread().getName()+"...wating...");
- try {
- lock.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- System.out.println(Thread.currentThread().getName()+"...flag is true");
- }
- });
- Thread t3 = new Thread(() -> {
- synchronized (lock) {
- System.out.println(Thread.currentThread().getName() + " hold lock");
- lock.notifyAll();
- flag = true;
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- t1.start();
- t2.start();
- t3.start();
- }
- }

难易程度:☆☆☆出现频率:☆☆☆
- public class WaitSleepCase {
- static final Object LOCK = new Object();
- public static void main(String[] args) throws InterruptedException {
- sleeping();
- }
- private static void illegalWait() throws InterruptedException {
- LOCK.wait();
- }
- private static void waiting() throws InterruptedException {
- Thread t1 = new Thread(() -> {
- synchronized (LOCK) {
- try {
- get("t").debug("waiting...");
- LOCK.wait(5000L);
- } catch (InterruptedException e) {
- get("t").debug("interrupted...");
- e.printStackTrace();
- }
- }
- }, "t1");
- t1.start();
- Thread.sleep(100);
- synchronized (LOCK) {
- main.debug("other...");
- }
- }
- private static void sleeping() throws InterruptedException {
- Thread t1 = new Thread(() -> {
- synchronized (LOCK) {
- try {
- get("t").debug("sleeping...");
- Thread.sleep(5000L);
- } catch (InterruptedException e) {
- get("t").debug("interrupted...");
- e.printStackTrace();
- }
- }
- }, "t1");
- t1.start();
- Thread.sleep(100);
- synchronized (LOCK) {
- main.debug("other...");
- }
- }
- }

难易程度:☆☆出现频率:☆☆
- public class MyInterrupt1 extends Thread {
- volatile boolean flag = false ; // 线程执行的退出标记
- @Override
- public void run() {
- while(!flag) {
- System.out.println("MyThread...run...");
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public static void main(String[] args) throws
- InterruptedException {
- // 创建MyThread对象
- MyInterrupt1 t1 = new MyInterrupt1() ;
- t1.start();
- // 主线程休眠6秒
- Thread.sleep(6000);
- // 更改标记为true
- t1.flag = true ;
- }
- }

- public class MyInterrupt2 extends Thread {
- volatile boolean flag = false ; // 线程执行的退出标记
- @Override
- public void run() {
- while(!flag) {
- System.out.println("MyThread...run...");
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public static void main(String[] args) throws InterruptedException {
- // 创建MyThread对象
- MyInterrupt2 t1 = new MyInterrupt2() ;
- t1.start();
- // 主线程休眠2秒
- Thread.sleep(6000);
- // 调用stop方法
- t1.stop();
- }
- }

③ 使用interrupt方法中断线程。
- package com.itheima.basic;
- public class MyInterrupt3 {
- public static void main(String[] args) throws InterruptedException {
- //1.打断阻塞的线程
- /*Thread t1 = new Thread(()->{
- System.out.println("t1 正在运行...");
- try {
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }, "t1");
- t1.start();
- Thread.sleep(500);
- t1.interrupt();
- System.out.println(t1.isInterrupted());*/
- //2.打断正常的线程
- Thread t2 = new Thread(()->{
- while(true) {
- Thread current = Thread.currentThread();
- boolean interrupted = current.isInterrupted();
- if(interrupted) {
- System.out.println("打断状态:"+interrupted);
- break;
- }
- }
- }, "t2");
- t2.start();
- Thread.sleep(500);
- // t2.interrupt();
- }
- }

难易程度:☆☆☆☆☆出现频率:☆☆☆
- public class TicketDemo {
- static Object lock = new Object();
- int ticketNum = 10;
- public synchronized void getTicket() {
- synchronized (this) {
- if (ticketNum <= 0) {
- return;
- }
- System.out.println(Thread.currentThread().getName() + "抢到一张票,剩余:" + ticketNum);
- // 非原子性操作
- ticketNum--;
- }
- }
- public static void main(String[] args) {
- TicketDemo ticketDemo = new TicketDemo();
- for (int i = 0; i < 20; i++) {
- new Thread(() -> {
- ticketDemo.getTicket();
- }).start();
- }
- }
- }

- public class SyncTest {
- static final Object lock = new Object();
- static int counter = 0;
- public static void main(String[] args) {
- synchronized (lock) {
- counter++;
- }
- }
- }
- monitorenter 上锁开始的地方
- monitorexit 解锁的地方
- 其中被monitorenter和monitorexit包围住的指令就是上锁的代码
- 有两个monitorexit的原因,第二个monitorexit是为了防止锁住的代码抛异常后不能及时释放锁
- static final Object obj = new Object();
- public static void method1() {
- synchronized (obj) {
- // 同步块 A
- method2();
- }
- }
- public static void method2() {
- synchronized (obj) {
- // 同步块 B
- }
- }
- static final Object obj = new Object();
- public static void m1() {
- synchronized (obj) {
- // 同步块 A
- m2();
- }
- }
- public static void m2() {
- synchronized (obj) {
- // 同步块 B
- m3();
- }
- }
- public static void m3() {
- synchronized (obj) {
-
- }
- }

描述
| |
重量级锁
|
底层使用的
Monitor
实现,里面涉及到了用户态和内核态的切换、进程的上下文切换,成本较高,性能比较低。
|
轻量级锁
|
线程加锁的时间是错开的(也就是没有竞争),可以使用轻量级锁来优
化。轻量级修改了对象头的锁标志,相对重量级锁性能提升很多。每次
修改都是
CAS
操作,保证原子性
|
偏向锁 |
一段很长的时间内都只被一个线程使用锁,可以使用了偏向锁,在第一次获得锁时,会有一个CAS
操作,之后该线程再获取锁,只需要判断 mark word中是否是自己的线程
id
即可,而不是开销相对较大的
CAS
命令
|
一旦锁发生了竞争,都会升级为重量级锁
难易程度:☆☆☆出现频率:☆☆☆
难易程度:☆☆☆出现频率:☆☆
一个当前内存值 V 、旧的预期值 A 、即将更新的值 B ,当且仅当旧的预期值 A和内存值V 相同时,将内存值修改为 B 并返回 true ,否则什么都不做,并返回false。如果 CAS 操作失败,通过自旋的方式等待并再次尝试,直到成功
难易程度:☆☆☆出现频率:☆☆☆
- package com.itheima.basic;
- // 可见性例子
- // -Xint
- public class ForeverLoop {
- static boolean stop = false;
- public static void main(String[] args) {
- new Thread(() -> {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- stop = true;
- System.out.println("modify stop to true...");
- }).start();
- foo();
- }
- static void foo() {
- int i = 0;
- while (!stop) {
- i++;
- }
- System.out.println("stopped... c:"+ i);
- }
- }

当执行上述代码的时候,发现foo()方法中的循环是结束不了的,也就说读取不到共享变量的值结束循环。
主要是因为在JVM虚拟机中有一个JIT(即时编辑器)给代码做了优化。
上述代码
while (!stop) { i++; }在很短的时间内,这个代码执行的次数太多了,当达到了一个阈值,JIT就会优化此代码,如下:
while (true) { i++; }当把代码优化成这样子以后,及时 stop 变量改变为了 false 也依然停止不了循环
static volatile boolean stop = false;
难易程度:☆☆☆出现频率:☆☆☆
Synchronized | AQS |
关键字,c++ 语言实现 | java 语言实现 |
悲观锁,自动释放锁 | 悲观锁,手动开启和关闭 |
锁竞争激烈都是重量级锁,性能差
|
锁竞争激烈的情况下,提供了多种解决方案
|
AQS常见的实现类
比较典型的 AQS 实现类 ReentrantLock ,它默认就是非公平锁,新的线程与队列中的线程共同来抢资源
难易程度:☆☆☆☆出现频率:☆☆☆
难易程度:☆☆☆☆出现频率:☆☆☆☆
难易程度:☆☆☆☆出现频率:☆☆☆
例如:t1 线程获得 A 对象锁,接下来想获取 B 对象的锁t2 线程获得 B 对象锁,接下来想获取 A 对象的锁
- package com.itheima.basic;
- import static java.lang.Thread.sleep;
- public class Deadlock {
- public static void main(String[] args) {
- Object A = new Object();
- Object B = new Object();
- Thread t1 = new Thread(() -> {
- synchronized (A) {
- System.out.println("lock A");
- try {
- sleep(1000);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- synchronized (B) {
- System.out.println("lock B");
- System.out.println("操作...");
- }
- }
- }, "t1");
- Thread t2 = new Thread(() -> {
- synchronized (B) {
- System.out.println("lock B");
- try {
- sleep(500);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- synchronized (A) {
- System.out.println("lock A");
- System.out.println("操作...");
- }
- }
- }, "t2");
- t1.start();
- t2.start();
- }
- }

控制台输出结果
难易程度:☆☆☆出现频率:☆☆☆
难易程度:☆☆☆出现频率:☆☆☆☆
难易程度:☆☆☆出现频率:☆☆☆
(3)内存可见性
难易程度:☆☆☆出现频率:☆☆☆☆
- import java.lang.reflect.Field;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.ArrayBlockingQueue;
- import java.util.concurrent.FutureTask;
- import java.util.concurrent.ThreadPoolExecutor;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.atomic.AtomicInteger;
-
- public class TestThreadPoolExecutor {
- static class MyTask implements Runnable {
- private final String name;
- private final long duration;
- public MyTask(String name) {
- this(name, 0);
- }
- public MyTask(String name, long duration) {
- this.name = name;
- this.duration = duration;
- }
- @Override
- public void run() {
- try {
- LoggerUtils.get("myThread").debug("running..." +
- this);
- Thread.sleep(duration);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- @Override
- public String toString() {
- return "MyTask(" + name + ")";
- }
- }
- public static void main(String[] args) throws
- InterruptedException {
- AtomicInteger c = new AtomicInteger(1);
- ArrayBlockingQueue<Runnable> queue = new
- ArrayBlockingQueue<>(2);
- ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
- 2,
- 3,
- 0,
- TimeUnit.MILLISECONDS,
- queue,
- r -> new Thread(r, "myThread" +
- c.getAndIncrement()),
- new ThreadPoolExecutor.AbortPolicy());
- showState(queue, threadPool);
- threadPool.submit(new MyTask("1", 3600000));
- showState(queue, threadPool);
- threadPool.submit(new MyTask("2", 3600000));
- showState(queue, threadPool);
- threadPool.submit(new MyTask("3"));
- showState(queue, threadPool);
- threadPool.submit(new MyTask("4"));
- showState(queue, threadPool);
- threadPool.submit(new MyTask("5",3600000));
- showState(queue, threadPool);
- threadPool.submit(new MyTask("6"));
- showState(queue, threadPool);
- }
- private static void showState(ArrayBlockingQueue<Runnable>
- queue, ThreadPoolExecutor threadPool) {
- try {
- Thread.sleep(300);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- List<Object> tasks = new ArrayList<>();
- for (Runnable runnable : queue) {
- try {
- Field callable =
- FutureTask.class.getDeclaredField("callable");
- callable.setAccessible(true);
- Object adapter = callable.get(runnable);
- Class<?> clazz =
- Class.forName("java.util.concurrent.Executors$RunnableAdapter");
- Field task = clazz.getDeclaredField("task");
- task.setAccessible(true);
- Object o = task.get(adapter);
- tasks.add(o);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- LoggerUtils.main.debug("pool size: {}, queue: {}",
- threadPool.getPoolSize(), tasks);
- }
- }

难易程度:☆☆☆出现频率:☆☆☆
LinkedBlockingQueue
|
ArrayBlockingQueue
|
默认无界,支持有界
|
强制有界
|
底层是链表
|
底层是数组
|
是懒惰的,创建节点的时候添加数据
|
提前初始化
Node
数组
|
入队会生成新
Node
|
Node
需要是提前创建好的
|
两把锁(头尾)
|
一把锁
|
左边是LinkedBlockingQueue加锁的方式,右边是ArrayBlockingQueue加锁的方式
难易程度:☆☆☆☆出现频率:☆☆☆
难易程度:☆☆☆出现频率:☆☆☆
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
-
- public class FixedThreadPoolCase {
- static class FixedThreadDemo implements Runnable{
- @Override
- public void run() {
- String name = Thread.currentThread().getName();
- for (int i = 0; i < 2; i++) {
- System.out.println(name + ":" + i);
- }
- }
- }
- public static void main(String[] args) throws
- InterruptedException {
- //创建一个固定大小的线程池,核心线程数和最大线程数都是3
- ExecutorService executorService =
- Executors.newFixedThreadPool(3);
- for (int i = 0; i < 5; i++) {
- executorService.submit(new FixedThreadDemo());
- Thread.sleep(10);
- }
- executorService.shutdown();
- }
- }

2. 单线程化的线程池,它只会用唯一的工作线程来执行任 务,保证所有任务按照指定顺序(FIFO)执行
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
-
- public class NewSingleThreadCase {
- static int count = 0;
- static class Demo implements Runnable {
- @Override
- public void run() {
- count++;
- System.out.println(Thread.currentThread().getName() + ":" +
- count);
- }
- }
- public static void main(String[] args) throws
- InterruptedException {
- //单个线程池,核心线程数和最大线程数都是1
- ExecutorService exec =
- Executors.newSingleThreadExecutor();
- for (int i = 0; i < 10; i++) {
- exec.execute(new Demo());
- Thread.sleep(5);
- }
- exec.shutdown();
- }
- }

3. 可缓存线程池
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
-
- public class CachedThreadPoolCase {
- static class Demo implements Runnable {
- @Override
- public void run() {
- String name = Thread.currentThread().getName();
- try {
- //修改睡眠时间,模拟线程执行需要花费的时间
- Thread.sleep(100);
- System.out.println(name + "执行完了");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public static void main(String[] args) throws
- InterruptedException {
- //创建一个缓存的线程,没有核心线程数,最大线程数为
- Integer.MAX_VALUE
- ExecutorService exec =
- Executors.newCachedThreadPool();
- for (int i = 0; i < 10; i++) {
- exec.execute(new Demo());
- Thread.sleep(1);
- }
- exec.shutdown();
- }
- }

4. 提供了“延迟”和“周期执行”功能的ThreadPoolExecutor。
- import java.util.concurrent.Executors;
- import java.util.concurrent.ScheduledExecutorService;
- import java.util.concurrent.TimeUnit;
-
- public class ScheduledThreadPoolCase {
- static class Task implements Runnable {
- @Override
- public void run() {
- try {
- String name =
- Thread.currentThread().getName();
- System.out.println(name + ", 开始:" + new
- Date());
- Thread.sleep(1000);
- System.out.println(name + ", 结束:" + new
- Date());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public static void main(String[] args) throws
- InterruptedException {
- //按照周期执行的线程池,核心线程数为2,最大线程数为
- Integer.MAX_VALUE
- ScheduledExecutorService scheduledThreadPool =
- Executors.newScheduledThreadPool(2);
- System.out.println("程序开始:" + new Date());
- /**
- * schedule 提交任务到线程池中
- * 第一个参数:提交的任务
- * 第二个参数:任务执行的延迟时间
- * 第三个参数:时间单位
- */
- scheduledThreadPool.schedule(new Task(), 0,
- TimeUnit.SECONDS);
- scheduledThreadPool.schedule(new Task(), 1,
- TimeUnit.SECONDS);
- scheduledThreadPool.schedule(new Task(), 5,
- TimeUnit.SECONDS);
- Thread.sleep(5000);
- // 关闭线程池
- scheduledThreadPool.shutdown();
- }
- }

难易程度:☆☆☆出现频率:☆☆☆
难易程度:☆☆☆出现频率:☆☆☆☆
- import java.util.concurrent.CountDownLatch;
-
- public class CountDownLatchDemo {
- public static void main(String[] args) throws
- InterruptedException {
- //初始化了一个倒计时锁 参数为 3
- CountDownLatch latch = new CountDownLatch(3);
- new Thread(() -> {
- System.out.println(Thread.currentThread().getName()+"-
- begin...");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- //count--
- latch.countDown();
- System.out.println(Thread.currentThread().getName()+"-
- end..." +latch.getCount());
- }).start();
- new Thread(() -> {
- System.out.println(Thread.currentThread().getName()+"-
- begin...");
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- //count--
- latch.countDown();
- System.out.println(Thread.currentThread().getName()+"-
- end..." +latch.getCount());
- }).start();
- new Thread(() -> {
- System.out.println(Thread.currentThread().getName()+"-
- begin...");
- try {
- Thread.sleep(1500);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- //count--
- latch.countDown();
- System.out.println(Thread.currentThread().getName()+"-
- end..." +latch.getCount());
- }).start();
- String name = Thread.currentThread().getName();
- System.out.println(name + "-waiting...");
- //等待其他线程完成
- latch.await();
- System.out.println(name + "-wait end...");
- }
- }

4.1.2 案例一(es数据批量导入)
在进行搜索的时候,需要保存用户的搜索记录,而搜索记录不能影响用户的正常搜索,我们通常会开启一个线程去执行历史记录的保存,在新开启的线程在执行的过程中,可以利用线程提交任务
难易程度:☆☆☆出现频率:☆☆
- import java.util.concurrent.Semaphore;
-
- public class SemaphoreCase {
- public static void main(String[] args) {
- // 1. 创建 semaphore 对象
- Semaphore semaphore = new Semaphore(3);
- // 2. 10个线程同时运行
- for (int i = 0; i < 10; i++) {
- new Thread(() -> {
- try {
- // 3. 获取许可
- semaphore.acquire();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- try {
- System.out.println("running...");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("end...");
- } finally {
- // 4. 释放许可
- semaphore.release();
- }
- }).start();
- }
- }
- }

难易程度:☆☆☆出现频率:☆☆☆☆
- public class ThreadLocalTest {
- static ThreadLocal<String> threadLocal = new ThreadLocal<>();
- public static void main(String[] args) {
- new Thread(() -> {
- String name = Thread.currentThread().getName();
- threadLocal.set("itcast");
- print(name);
- System.out.println(name + "-after remove : " +
- threadLocal.get());
- }, "t1").start();
- new Thread(() -> {
- String name = Thread.currentThread().getName();
- threadLocal.set("itheima");
- print(name);
- System.out.println(name + "-after remove : " +
- threadLocal.get());
- }, "t2").start();
- }
- static void print(String str) {
- //打印当前线程中本地内存中本地变量的值
- System.out.println(str + " :" + threadLocal.get());
- //清除本地内存中的本地变量
- threadLocal.remove();
- }
- }

在jdk1.7中 ConcurrentHashMap 里包含一个 Segment 数组。Segment 的结构和HashMap类似,是一 种数组和链表结构,一个 Segment 包含一个HashEntry 数组,每个 HashEntry 是一个链表结构 的元素,每个 Segment 守护着一个HashEntry数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment的锁。
面试官:你在项目中哪里用了多线程?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。