多线程

线程的生命周期

一、实现多线程的三种方式

  1. 继承Thread类
  2. 实现Runnable接口
  3. 实现Callable接口方式(有返回值)

二、start()方法和run()方法的区别

只有调用了start()方法,才会表现出多线程的特性,不同线程的run()方法里面的代码交替执行。如果只是调用run()方法,那么代码还是同步执行的,必须等待一个线程的run()方法里面的代码全部执行完毕之后,另外一个线程才可以执行其run()方法里面的代码

三、Runnable接口和Callable接口的区别

Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果

四、sleep方法和wait方法有什么区别

  1. 对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。
  2. sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。

而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备,获取对象锁进入运行状态。

  • notify 和 notifyAll有什么区别?

notify()方法不能唤醒某个具体的线程,所以只有一个线程在等 待的时候它才有用武之地。而notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行

五、Lock和synchronized的不同?

  1. lock是一个接口,synchronized是一个关键字。
  2. synchroized在遇到异常时,会自动释放线程占有的锁,因此不会导致死锁的发生;而lock发生异常时,如果没有主动unLock()去释放锁,很可能造成死锁现象,unLock要放到finally块里执行;
  3. Lock可以让等待锁的线程响应中断,线程可以中断去干别的事务,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断
  4. 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

示例:

/**

* 这样效率不高,只能一个人吃,吃的方法为同步方法了

* @author Administrator

*/

public class Apple implements Runnable{

    private int num=50;

    public void run() {

        for(int i=0;i<50;i++){

            eat();

        }

    }

    private synchronized void eat() {

        if (num > 0) {

            try {

                // 导致一个资源信息被多个用户同时拿到

                Thread.sleep(20);

            } catch (InterruptedException e) {

                e.printStackTrace();

        }

        System.out.println(Thread.currentThread().getName() + "吃了编号为" + num + "的苹果");

        num--;

        }

    }

    public static void main(String[] args) {

        Apple a=new Apple();

        new Thread(a,"A").start();
    
        new Thread(a,"B").start();

        new Thread(a,"C").start();

    }

}

//-----------------------------------------------------

public class Apple2 implements Runnable{

    private int num=50;

    private final Lock lock = new ReentrantLock();

    public void run() {

        for(int i=0;i<50;i++){

        eat();

        }

    }

    private void eat() {

        lock.lock();//获取锁

        if (num > 0) {

            try {

                System.out.println(Thread.currentThread().getName() + "吃了编号为" + num + "的苹果");

                // 导致一个资源信息被多个用户同时拿到

                Thread.sleep(20);

                num--;

            } catch (InterruptedException e) {

                e.printStackTrace();

            } finally{

                lock.unlock();//释放锁

            }
    
        }

    }

    public static void main(String[] args) {

        Apple2 a=new Apple2();

        new Thread(a,"A").start();

        new Thread(a,"B").start();

        new Thread(a,"C").start();

    }

}

六、volatile作用

  1. 其他线程对变量的修改,可以及时反应在当前线程中;
  2. 确保当前线程对volatile变量的修改,能及时写回到共享内存中,并被其他线程所见;
  3. 使用volatile声明的变量,编译器会保证其有序性。

七、线程池

  • 包括以下四个基本组成部分
  1. 线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
  2. 工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
  3. 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
  4. 任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
  • 为什么要用线程池:
  1. 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  2. 可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

八、Lock接口

  1. ReadLock
  2. ReentrantLock
  3. WriteLock

ReentrantLock的使用:

Lock lock = new ReentrantLock(); lock.lock(); try{ //可能会出现线程安全的操作 }finally{ //一定在finally中释放锁 //也不能把获取锁在try中进行,因为有可能在获取锁的时候抛出异常 lock.ublock(); }

九、线程池

  1. 为什么要用线程池:

1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。

2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

  1. 比较重要的几个类:

1. newSingleThreadExecutor

创建一个单线程的线程池

2.newFixedThreadPool

创建固定大小的线程池。

3. newCachedThreadPool

创建一个可缓存的线程池。

4.newScheduledThreadPool

创建一个大小无限的线程池。

十、锁机制

  1. 重入锁:目的是为防止死锁发生。synchronized和Lock均为可重入锁
  2. 自旋锁:线程被阻塞为系统阻塞,处于内核态,java执行为用户态;为避免经常在用户态和内核态频繁切换导致性能下降,实现了自旋锁
  3. 偏向锁:线程加锁操作采用CAS操作。当线程已经获得锁后,再重入该锁时,后续操作将不会采用CAS,因为不存在锁竞争。

https://blog.csdn.net/dainandainan1/article/details/85267740

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值