JAVA面试汇总(二)多线程(五)

JAVA多线程内容比较多,今天写完了第五篇,后边还有六。

  1. 对象锁和类锁是否会互相影响?
    (1)我前面讲过的,带有synchronized的static方法,必须单独执行,无论是多个实例操作,只要访问统一方法,都需要等待迁移执行完毕
    (2)但是当访问的是带synchronized的普通方法(对象锁),这种如果创建多个实例,互相是不干扰的,可以并行执行,但是同一个实例的情况下需要等待前一个执行完毕才能下个执行
    (3)多个实体同时有类锁以及对象锁时候,也是互补干扰的,类锁实际锁的是静态的同步方法,如果不调用同步方法,就不会影响,也就是各自锁各自的。

    public class TwoSynchronized {
    public static synchronized void method1() {
    try {
    System.out.println(Thread.currentThread().getName() + " method1 started");
    Thread.sleep(500);
    System.out.println(Thread.currentThread().getName() + " method1 end");
    }catch (Exception e){

    复制代码
         }
     }
     public synchronized void method2() {
         try {
             System.out.println(Thread.currentThread().getName()+" method2 started");
             Thread.sleep(500);
             System.out.println(Thread.currentThread().getName()+" method2 end");
         }catch (Exception e){
    
         }
     }
     public static void main(String[] args) throws InterruptedException {
         for (int i = 0; i < 10; i++) {
             TwoSynchronized one = new TwoSynchronized();
             new Thread(new Runnable() {
                 @Override
                 public void run() {
                     one.method1();
                 }
             }).start();
         }
         for (int i = 0; i < 10; i++) {
             TwoSynchronized two = new TwoSynchronized();
             new Thread(new Runnable() {
                 @Override
                 public void run() {
                     two.method2();
                 }
             }).start();
         }
         Thread.sleep(100000);
     }

    }
    //输出,可以看出method1和method2同时执行了
    //说明了类锁存在的情况下,对象锁还可以同时执行
    Thread-0 method1 started
    Thread-10 method2 started
    Thread-11 method2 started
    Thread-14 method2 started
    Thread-15 method2 started
    Thread-18 method2 started
    Thread-19 method2 started
    Thread-12 method2 started
    Thread-13 method2 started
    Thread-16 method2 started
    Thread-17 method2 started
    Thread-13 method2 end
    Thread-11 method2 end
    Thread-0 method1 end
    Thread-12 method2 end
    Thread-14 method2 end
    Thread-15 method2 end
    Thread-18 method2 end
    Thread-19 method2 end
    Thread-16 method2 end
    Thread-17 method2 end
    Thread-9 method1 started
    Thread-10 method2 end
    Thread-9 method1 end
    Thread-7 method1 started
    Thread-7 method1 end
    Thread-6 method1 started
    Thread-6 method1 end
    Thread-3 method1 started
    Thread-3 method1 end
    Thread-2 method1 started
    Thread-2 method1 end
    Thread-8 method1 started
    Thread-8 method1 end
    Thread-5 method1 started
    Thread-5 method1 end
    Thread-4 method1 started
    Thread-4 method1 end
    Thread-1 method1 started
    Thread-1 method1 end

  2. Java中ConcurrentHashMap的并发度是什么?

    ConcurrentHashMap把实际map划分成若干部分来实现它的可扩展性和线程安全。这种划分是使用并发度获得的,它是ConcurrentHashMap类构造函数的一个可选参数,默认值为16。注意注意,这个仅限于JDK1.7,在JDK1.8不用分段了,用的CAS方式重试去写入,所以不存在并发度了。

  3. 什么是Java Timer类?如何创建一个有特定时间间隔的任务?

    (1)java.util.Timer 是一个工具类,可以用于安排一个线程在未来的某个特定时间执行。Timer类可以用安排一次性任务或者周期任务。

    (2)Timer有几个schedule方法,可以设定指定时间执行,或者指定间隔执行等操作。

    (3)schedule(TimerTask task, Date time),其中TimerTask表示需要执行的任务。

    import java.util.Timer;
    import java.util.TimerTask;

    public class TimerTest01 {
    public TimerTest01(int time){
    Timer timer = new Timer();
    timer.schedule(new TimerTaskTest01(), time * 1000);
    System.out.println(time * 1000);
    }
    public static void main(String[] args) {
    System.out.println("timer begin....");
    // 3秒后执行内部具体任务
    new TimerTest01(3);
    System.out.println("timer end....");
    }
    static class TimerTaskTest01 extends TimerTask {
    public void run() {
    // 执行的任务
    System.out.println("Time's up!!!!");
    }
    }
    }

  4. SimpleDateFormat是线程安全的吗?
    (1)SimpleDateFormat底层实现是用的Calendar,其中parse时候调用了CalendarBuilder.establish()方法,
    (2)其中先后调用了cal.clear()与cal.set(),这样就把静态实体的值修改了,所以在多线程parse过程中导致了问题。
    (3)那么如何避免呢:需要使用局部变量,每个线程种,都单独创建SimpleDateFormat;

    复制代码
                     try {
                         SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH");
                         System.out.println(simpleDateFormat.parse("2020-01-01 15"));
                     } catch (ParseException e) {
                         System.out.println("线程:" + Thread.currentThread().getName() + " 格式化日期失败");
                         e.printStackTrace();
                         System.exit(1);
                     }

(4)另外一种为parse的前后,SimpleDateFormat对加锁

复制代码
                    try {
                        synchronized (simpleDateFormat){
                            simpleDateFormat.parse("2020-01-01");
                        }
                    } catch (ParseException e) {
                        System.out.println("线程:" + Thread.currentThread().getName() + " 格式化日期失败");
                        e.printStackTrace();
                        System.exit(1);
                    }

(4)执行前加Lock.lock,执行完成后unlock

(5)通过ThreadLocal,每个线程独立的simpleDateFormat

复制代码
//在线程run方法同级别创建threadlocal
    private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>(){
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd");
        }
    };
//run方法中实现,每个线程过来,通过threadLocal中取出来,但是这种和上面(3)每个线程创建独立的SimpleDateFormat没有区别吧?
//如果这条有异议可以给我评论,咱们再讨论
                    try {
                        threadLocal.get().parse("2020-01-01");
                    } catch (ParseException e) {
                        System.out.println("线程:" + Thread.currentThread().getName() + " 格式化日期失败");
                        e.printStackTrace();
                        System.exit(1);
                    }
  1. 用Java写一个会导致死锁的程序,你将怎么解决?
    (1)两个线程分别都要锁定两个变量
    (2)两个线程分别都获取锁定了一个变量,各自不同
    (3)两个线程分别都等待对方释放另一个变量,结果谁也不会释放,就死锁了

    public class TestDeadLock {
    public static void main(String[] args) {
    Object a = new Object();
    Object b = new Object();
    Thread runnableA = new Thread(new Runnable() {
    @Override
    public void run() {
    synchronized (a){
    System.out.println("runnable a lock a");
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("runnable a waiting b");
    synchronized (b){
    System.out.println("runnable a lock b");
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    }
    });
    Thread runnableB = new Thread(new Runnable() {
    @Override
    public void run() {
    synchronized (b){
    System.out.println("runnable b lock b");
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("runnable b waiting a");
    synchronized (a){
    System.out.println("runnable b lock a");
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    }
    });
    runnableA.start();
    runnableB.start();
    }
    }
    //输出
    runnable b lock b
    runnable a lock a
    runnable a waiting b
    runnable b waiting a
    //后边就一直互相等待了

(4)所以应该尽量避免多线程执行中,一个线程锁定多个

(5)如果必须要锁定多个,那么尽量要锁定顺序一致

(6)使用定时锁tryLock,一段时间以后timeout会释放锁

复制代码
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TestDeadLock {
    static ReentrantLock a = new ReentrantLock();
    static ReentrantLock b = new ReentrantLock();
    public static void main(String[] args) {

        Thread runnableA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    a.tryLock(10, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("runnable a lock a failed");
                    return;
                }
                System.out.println("runnable a lock a");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("runnable a waiting b");
                try {
                    b.tryLock(10, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("runnable a lock b failed");
                    return;
                }
                System.out.println("runnable a lock b");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread runnableB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    b.tryLock(5, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("runnable b lock b failed");
                    return;
                }
                System.out.println("runnable b lock b");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("runnable b waiting a");
                try {
                    a.tryLock(5, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("runnable b lock a failed");
                    return;
                }
                System.out.println("runnable b lock a");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        runnableA.start();
        runnableB.start();
    }
}
//输出
runnable a lock a
runnable b lock b
runnable a waiting b
runnable b waiting a
runnable b lock a
runnable a lock b

谢各位的阅读,谢谢您动动手指点赞,万分感谢各位。另外以下是我之前写过的文章,感兴趣的可以点进去继续阅读。

历史文章

Hadoop系列-入门安装
Hadoop系列-HDFS命令
Hadoop系列-Hive安装
Hadoop系列-Hive数据库常见SQL命令
Hadoop系列-HBase数据库
Hadoop系列-HBase数据库(二)
Hadoop系列-HBase数据库JAVA篇
Hadoop系列-Spark安装以及HelloWorld
JAVA面试汇总(五)数据库(一)
JAVA面试汇总(五)数据库(二)
JAVA面试汇总(五)数据库(三)
JAVA面试汇总(四)JVM(一)
JAVA面试汇总(四)JVM(二)
JAVA面试汇总(四)JVM(三)
JAVA面试汇总(三)集合(一)
JAVA面试汇总(三)集合(二)
JAVA面试汇总(三)集合(三)
JAVA面试汇总(三)集合(四)
JAVA面试汇总(二)多线程(一)
JAVA面试汇总(二)多线程(二)
JAVA面试汇总(二)多线程(三)
JAVA面试汇总(二)多线程(四)
JAVA面试汇总(二)多线程(五)
JAVA面试汇总(二)多线程(六)
JAVA面试汇总(二)多线程(七)
JAVA面试汇总(一)Java基础知识
最后编辑于:2025-08-30 16:26:05
© 著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务

喜欢的朋友记得点赞、收藏、关注哦!!!

相关推荐
咖啡の猫3 小时前
Vue初始化脚手架
前端·javascript·vue.js
一 乐3 小时前
汽车销售|汽车推荐|基于SprinBoot+vue的新能源汽车个性化推荐系统(源码+数据库+文档)
java·数据库·vue.js·汽车·毕设·汽车个性化推荐
晨枫阳3 小时前
uniapp兼容问题处理总结
前端·vue.js·uni-app
JustNow_Man4 小时前
Cline中模型识别任务与clinerules相关性的实现逻辑
linux·运维·ubuntu
小白银子4 小时前
零基础从头教学Linux(Day 56)
linux·运维·python
你想考研啊4 小时前
Linux下搭建Activemq的Master-Slave(共享文件模式)
linux·运维·activemq
兜兜风d'4 小时前
RabbitMQ 持久性详解
spring boot·分布式·rabbitmq·1024程序员节
Teamhelper_AR4 小时前
AR巡检系统:打开工业智能运维的下一幕
运维·ar
道阻且长行则将至!4 小时前
ubuntu中为什么查看CPU的步进?查看命令是什么?
linux·运维·ubuntu·步进·stepping