JAVA多线程2(学习自用)

目录

一、JAVA各种锁

1、乐观锁

2、悲观锁

3、重量级锁

4、轻量级锁

5、偏向锁

6、可重入锁

二、JAVA方法

1、wait和notify、notifyAll

​编辑

2、stop

3、interrupt

4、java如何加锁

1)传统锁

2)读写锁


一、JAVA各种锁

1、乐观锁

含义:认为当前线程在处理数据时,没有其他数据来改变数据,故一开始不加锁。

实现方式:

1)CAS(比较并替换)

2)版本号控制

2、悲观锁

含义:认为当前线程在处理数据时会有其他线程同时来改变数据,一开始会加锁。

实现方法:synchronized、lock

3、重量级锁

一个线程自旋多圈(默认为15次),线程就进入等待状态,这个线程看待锁对象就是重量级锁。

4、轻量级锁

一个线程运行到一个以A对象为锁的同步代码块,已经有线程获取了锁对象的权限,当前线程就要等待获取锁对象的权限,这时线程就会循环获取锁对象的同意,这是线程看待所对象就是一个轻量级锁。

5、偏向锁

含义:线程进入A对象为锁的同步代码块,内部又进入以A对象为锁的同步代码块,该线程看待这个A锁对象就是偏向锁。

6、可重入锁

线程执行同步代码块,已经获取锁对象的权限,内部在执行到该对象为锁的同步代码块,就不需要再获取该对象的权限了,java中都是可重入锁。

二、JAVA方法

1、wait和notify、notifyAll

看下面代码理解这些方法:
 

 static Object obj=new Object();
    static Runnable ra=()->{
        synchronized (obj){
            System.out.println("A----进入方法");
            try {
//                Thread.sleep(3000);
                obj.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("A----结束方法");
        }
    };
    static Runnable rb=()->{
        synchronized (obj){
            System.out.println("B----进入方法");
            System.out.println("B----结束方法");
            obj.notify();
        }
    };

    public static void main(String[] args) {
        Thread a=new Thread(ra);
        Thread b=new Thread(rb);
        a.start();
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        b.start();
    }

 最终结果为:

2、stop

用于立即停止线程的执行。这个方法已经被标记为废弃(deprecated),因为它可能会导致一些资源无法正常释放,从而引发资源泄露或其他不可预测的行为。

方法会立即终止线程,不考虑线程当前正在执行的操作。这可能导致线程在执行中间被中断,从而留下未完成的任务或未释放的资源。

3、interrupt

Thread类的一个方法,用于中断线程。它不会立即停止线程,而是设置线程的中断状态。线程可以通过检查中断状态来决定何时安全地停止自己。

interrupt()方法不会立即终止线程,而是设置线程的中断状态。线程可以在合适的位置检查中断状态,然后优雅地停止自己。

    //结束线程
    //1、stop
    //2、interrupt  标记此线程可中断,isInterrupted判断是否可中断
      //如果为true 就可以抛异常或结束代码
    //3、借鉴interrupt方法的作用,自定义一个标记变量,实现判断中断效果

    public static void main(String[] args){
        Runnable run=new EasyD()::test;
        Thread t=new Thread(run);
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //这个方法即将被取消
//        t.stop();


        //此方法不能直接结束线程,执行此方法,只是在线程对象中记录线程的状态是
        //可以被中断的,在线程执行体(run)内部,可以使用方法获取线程是否可中断
        //如果获取可中断的结果,就可以跳出循环获取抛出异常中断此线程
        t.interrupt();
    }
    public void test(){
        while(true){
            System.out.println("A----------------");
            if(Thread.currentThread().isInterrupted()){
                //isInterrupted()返回的是true,说明此线程对象在外部已经执行了
                //interrupt方法
                break;
            }
        }
    }

4、java如何加锁

1)传统锁

//Lock
    ReentrantLock lock=new ReentrantLock();
    public void test(){
        //加锁
        //lock.lock();
        while(!lock.tryLock()){  //tryLock尝试获取锁对象 获取到返回true 更加灵活
            System.out.println(Thread.currentThread().getName()
                    +"尝试获取锁对象");
        }
        for(int i=0;i<20;i++){
            System.out.println(Thread.currentThread().getName()
            +"---"+i);
        }
        //解锁
        lock.unlock();
    }

    public static void main(String[] args) {
        Runnable run=new EasyE()::test;
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        a.start();
        b.start();

    }

2)读写锁

  //读写锁
    ReentrantReadWriteLock lockbox=new ReentrantReadWriteLock();
    public void testRead(){
        Lock readLock=lockbox.readLock();
        readLock.lock();
        for(int i=0;i<20;i++){
            System.out.println(Thread.currentThread().getName()+
                    "----"+i);
        }
        readLock.unlock();
    }
    public void testWrite(){
        Lock writeLock=lockbox.writeLock();
        writeLock.lock();
        for(int i=0;i<20;i++){
            System.out.println(Thread.currentThread().getName()+
                    "----"+i);
        }
        writeLock.unlock();
    }

    public static void main(String[] args) {
        EasyF easyF=new EasyF();
        Runnable run=easyF::testRead;
        Runnable runW=easyF::testWrite;
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        Thread c=new Thread(run);
        Thread w=new Thread(runW);
        Thread w1=new Thread(runW);
        w.setName("Write");
        w1.setName("Write1");
        a.start();
        b.start();
        c.start();
        w.start();
        w1.start();
        //写锁  是一个独占锁  其他线程获取不到读锁和写锁
        //读锁  共享锁       只能对读操作共享
    }

上面代码在写锁过程中是不会有其他操作的,在读锁过程中可能有多个读锁交叉运行。

三、线程池

1、什么是线程池?

线程池本质是一个容器,可以实现线程的重用,提高对线程的利用率。

传统是每次执行一个任务时就创建一个线程,线程执行完任务就自己销毁。

而线程池是每次执行任务时就从线程池取出一个空闲线程执行任务,执行完任务后线程并不会销毁,而是返回线程池,以供执行下次任务时再使用。

2、线程池的作用?

1)在线程安全的条件下提高执行效率。

2)减少线程创建和线程销毁。

3)提高程序的可维护性和可扩展性。

3、如何创建线程池?

1)创建线程池

ExecutorService es=new ThreadPoolExecutor(5,8,1
        , TimeUnit.MINUTES, new LinkedBlockingQueue(),Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

2)线程池执行任务

//执行任务
        //Runnable 重写run方法
        //Callable 重写call方法
        Runnable run=()->{
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"---Run");
        };
        Callable<String> call=()->{
            Thread.sleep(3000);
            System.out.println(Thread.currentThread().getName()+"---Call");
            return "Easy";
        };
        //execute  只能执行Runnable  没有返回值
//        es.execute(run);

        //submit方法 可以处理Runnable、Callable
        //返回Future Future中有一个get方法可以获取执行结果,同时get方法会挂起并等待线程
        //执行完毕
        //submit处理Runnable,返回的是null值,Callable返回的值就是什么值
//        Future futureRun=es.submit(run);
        Future futureCall=es.submit(call);
        try {
            System.out.println("-----------------------------");
            Object obj=futureCall.get();
            System.out.println(obj);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

4、线程池的7个参数?

//1、核心线程数量
//2、最大线程数量
//3、存活时间
//4、时间单位
//5、工作队列
//6、线程工厂
//7、回绝策略

5、线程池的工作原理?

1)开始执行一个线程任务时,线程池会分配一个空闲线程去执行任务;

2)当任务过多且核心线程都已经分配任务时,此时若再执行任务,会将任务放到工作队列中去,若有核心线程运行完空闲时,逐个处理工作队列中的任务;

3)若有新的任务且核心线程和工作队列都已经满了的时候,会启用新的线程(但线程总数不能超过最大线程数量)去执行;

4)若有新的任务且此时所有线程(最大线程数量)和工作队列都运行时,会执行回绝策略,回绝策略有四种,如:抛出异常、不做任何反应、让发布者执行、删除工作队列头部的任务并插入新任务。

5)如果有线程空闲,并且线程数量超过核心线程数,就对该线程进行计时,达到最大存活时间, 就将该线程消亡掉,直到池中线程数量达到核心线程数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值