小卜java

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

2022-03-11  本文已影响0人  汤太咸啊

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

  2. 什么是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!!!!");
        }
    }
}
  1. 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基础知识

上一篇 下一篇

猜你喜欢

热点阅读