线程的创建方式

多线程创建、开启的四种方式

  1. 继承Thread类
    public static void main(String[] args) {

        //创建继承Thread类的自定义对象
        MyThread myThread = new MyThread();
        //调用start方法开启线程
        myThread.start();
    }
    
   自定义线程类继承Thread,重写run方法
   class MyThread extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(i);

        }
    }
}
  1. 实现Runnable接口
	//创建自定义线程类
        MyRunnable myRunnable = new MyRunnable();
        //创建线程类并指定任务
        Thread t1 = new Thread(myRunnable);
        Thread t2 = new Thread(myRunnable);
        //开启
        t1.start();
        t2.start();
	//实现Runnable接口并重写run方法
class MyRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
    }
}
  1. 实现Callable接口
        MyCallable myCallable = new MyCallable();
        //由Callable<Integer>创建一个FutureTask<Integer>对象
        FutureTask<Integer> task = new FutureTask<>(myCallable);
        //由FutureTask<Integer>创建一个Thread对象:
        Thread thread = new Thread(task);
        thread.start();

	//callable接口类,指定泛型
	class MyCallable implements Callable<Integer> {
    
    @Override
    public Integer call() throws Exception {
        //可以抛出异常
        //具有返回值
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
        return null;
    }
}
  1. 线程池
		//从线程池中获取两个线程
        ExecutorService es = Executors.newFixedThreadPool(2);
        //提交任务,可以是Callable接口也可以是Runable接口
       Future<Integer> future1 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 0; i < 50; i++) {
                    sum += i;
                }

                return sum;
            }
        });

泛型

实例泛型
在你这个类被创建成对象的时候被指定
静态泛型
不需要创建对象直接可以指定泛型

1、Java中Runnable和Callable有什么不同?

  • 相同点
    1. 都是接口
    2. 都可以编写多线程程序
    3. 都采用start方法启动
  • 不同点
  1. Runnable没有返回值;Callable可以返回执行结果,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果
  2. Callable接口的call()方法允许抛出异常;Runnable的run()方法异常只能在内部消化,不能往上继续抛
    :Callalbe接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。

2、线程共有几种状态?分别是?

  • New 初始状态
  • Runnable 可运行状态
  • Blocked 阻塞状态
  • Waiting 无限期等待
  • TimedWaiting 有限期等待
  • Terminate 终止状态

3、什么是线程池?为什么要使用它?

线程入容器,可设定线程分配的数量上限
将预先创建的线程对象存入池中,并重用线程池中额线程对象
避免频繁的创建和销毁

减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
案例
	   //从线程池中获取两个线程
        ExecutorService es = Executors.newFixedThreadPool(2);
	   //提交任务
        Future<Integer> future1 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 0; i < 50; i++) {
                    sum += i;
                }
                return sum;
            }
        });
        Future<Integer> future2 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 50; i <= 100; i++) {
                    sum += i;
                }
                return sum;
            }
        });

	   //获取返回值
        Integer result1 = future1.get();
        Integer result2 = future2.get();

        System.out.println(result1 + result2);
需求
子线程执行完毕之后,主线程才执行

ExecutorService中的方法

1.shutdown()方法
启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。
2.isTerminated() 
如果所有任务在关闭后完成,则返回 true 。 

对以上的代码进行修改
线程提交任务之后
        //结束继续提交
        es.shutdown();

        //判断子线程是否执行完毕
        while (!es.isTerminated()) {
            System.out.println("还没执行完");
        }

4、什么是线程不安全?

多个线程并发访问临界资源(一次仅允许一个进程使用的资源),破坏原子操作

5、保证线程安全的方法

  • 同步synchronized
  • 锁Lock 创建lock的对象Lock lock = new ReentrantLock();
    注意:lock.unlock必须在finally里释放。否则会造成死锁

6、Java中的ReentrantLock与ReentrantReadWriteLock有什么区别?

ReentrantLock:重入锁,lock接口的实现类
ReentrantReadWriteLock:读写锁,一种支持一写多度的同步锁,支持多次分配读锁,是多个读操作可以并发执行
互斥规则:

  • 写-写:互斥,阻塞
  • 读-写:互斥,读阻塞写,写阻塞读
  • 读-读:不互斥,不阻塞
        ReentrantReadWriteLock rw = new ReentrantReadWriteLock();
        //获取读锁
        ReadLock readLock = rw.readLock();
        //获取写锁
        WriteLock writeLock = rw.writeLock();

7、什么是ThreadLocal变量?实现原理是什么?

ThreadLocal里面是一个map,可以值存的是当前的ThreadLocal的地址
在这里插入图片描述

8、局部内部类访问外部类的局部变量必须加final

原因:两者生命周期可能不一致,内部类对象的生命周期会大于外部类的局部变量

9、如何获得一个线程安全的List集合?

Vector、Collections.synchronizedXXX(XXX)、CopyOnWriteArrayList、CopyOnWriteArraySet、ConcurrentHashMap

获取线程安全的list集合
List<Integer> list = Collections.synchronizedList(new ArrayList<>());

CopyOnWriteArrayList<String> list=  new CopyOnWriteArrayList();
list.add("aaa");
其他的一样

10、有哪些线程安全集合的执行效率高?

CopyOnWriteArrayList、CopyOnWriteArraySet、ConcurrentHashMap

11、CopyOnWriteArrayList是实现原理是什么?

CopyOnWriteArraySet集合的底层就是使用的list,只不过调用的是list的addIfAbsent()方法,原理相同

写操作加了锁,读操作不加锁
所以说写写互斥,读写不互斥

public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            //创建一个新的数组,用于写操作,避免读写操作发生不一致,读操作读到是旧数组
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

12、ConcurrentHashMap的实现原理是什么?

segment<key,value>[]
最高支持16个线程并发

ConcurrentHashMap将锁进行了更细粒度的划分
实行分段加锁,16个段有16把锁 JDK7,JDK8,CAS比较交换算法

在这里插入图片描述

13、ConcurrentLinkedQueue的实现原理是什么?

  • 线程安全,可高效读写的队列,高并发下性能最好的队列
  • CAS 比较交换算法,修改的方法包括三个核心参数(V,E,N)
  • V 要更新的变量,E 预期值,N 新值
  • 只有当V==E时,进行交换,V=N,否则表示更新过,去消当前的操作

AtomicInteger:线程安全
构造方法
在这里插入图片描述

        //创建线程安全的AtomicInteger对象
        AtomicInteger n = new AtomicInteger(0);

        //从线程池中获取两个线程
        ExecutorService es = Executors.newFixedThreadPool(2);

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    //调用++方法
                    n.getAndAdd(1);
                }
            }
        };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值