Java篇(八)

目录

1.线程的创建

2.中断线程

3.同步

3.1锁

3.2条件对象

3.3对象锁synchronized

3.4字段锁volatile

3.5原子性

3.6死锁

3.7线程局部变量ThreadLocal

4.线程安全

4.1阻塞队列

5.线程池


1.线程的创建

使用场景:在一个页面同时下载多个图片;服务器同时相应多个请求...

创建:1.创建一个类使用Runnable接口,将所要执行的内容放在run()方法中。2.创建Runnable对象,将它放在一个线程对象Thread中。3.运行该线程对象。

由于Runnable接口只有一个方法,所以可以使用lambda表达式。

    @Test
    void easyThread(){
        Runnable task1=()->{

            int i;
            for (i=0;i<100;i++){
                logger.info("task1");
            }
            logger.info(String.valueOf(i));

        };
        Runnable task2=()->{
            int i;
            for (i=0;i<100;i++) {
                logger.info("task2");
            }
            logger.info(String.valueOf(i));
        };
        new Thread(task1).start();
        new Thread(task2).start();
    }
//2个任务交替执行

2.中断线程

中断使用t.interrupt()。获取当前线程用Thread.currentThread()。

判断状态:1.判断特定线程的状态,t.isInterrupted() ; 2.判断当前线程的状态,Thread.interrupted(), 这一判断会将中断状态重置为false

其他方法可在官方文档查询:JDK 19 Documentation - Home

            System.out.println(Thread.currentThread());
            Thread.currentThread().interrupt();
            System.out.println(Thread.interrupted());//true
            System.out.println(Thread.interrupted());//false
            System.out.println(Thread.currentThread().isInterrupted());//false

3.同步

3.1锁

由于各线程可以公用资源,当多个线程需要对同一变量改动时极易产生错乱的风险。

ReentrantLock是重入锁,一个被锁保护的代码可以调用另一个使用相同锁的代码,避免创建更多新锁。

锁必须在finally语句中释放,避免因为异常而跳转。

(这里的lock相当于mutex)

var lock=new ReentrantLock();
        Runnable task1=()->{
            lock.lock();
            try {
               //
            }finally {
                lock.unlock();
            }
        };

3.2条件对象

满足某个条件或获得某种资源后才可以进行,此时可以使用Condition。(相当于semaphore)

    ReentrantLock lock=new ReentrantLock();
    Condition s=lock.newCondition();
    
        Runnable producer=()->{
            lock.lock();
        try{
            while (empty.get() <1) {
                    s.await();
            }
            ...
            s.signalAll()
        } finally{lock.unlock();} 
      
        }    

Condition必须在lock()之后只用;lock用于互斥,Condition用于同步

3.3对象锁synchronized

每个对象都有一个锁,隐式锁,代替lock,简化代码。放在方法的返回值的前面,表示这个方法不能同时被两个线程调用。条件是 wait(); notifyAll();

    public synchronized void addI(int i) throws InterruptedException {
        while (this.i+i>10)
            wait();
        this.i +=i;
        notifyAll();
    }

3.4字段锁volatile

当需要在get和set方法前加synchronized时,可直接在字段前加volatile代替

 private volatile int i;

等效于

    public synchronized int getI() {
        return i;
    }

    public synchronized void setI(int i) {
        this.i = i;
    }

3.5原子性

将变量声明为原子类,它们进行数值变化时不会被打断。这些类使用高效的机器指令,执行速度更快。

    public static AtomicInteger n=new AtomicInteger(6);
    public static int n2=n.incrementAndGet();

3.6死锁

程序挂起时,Ctrl+\可以查看所有线程,找到哪里阻塞。

3.7线程局部变量ThreadLocal

有时需要避免共享变量,为每个线程设计单独的对象,但这样又很低效,可以使用ThreadLocal

public  class Main{
 public static final ThreadLocal<SimpleDateFormat> format=ThreadLocal.withInitial(()->new SimpleDateFormat("yyyy-MM-dd"));

//...

  Runnable task2=()->{
            String d1=format.get().format(new Date());
//...
}
}

4.线程安全

4.1阻塞队列

BlockingQueue,操作方法类似list,是condition的改进版,对队列操作及其有用。

    public void operation() throws InterruptedException {
        String str1=queue.take(); //没有将等待
        queue.put("aa"); //放不下将等待

        String str2= queue.poll(30, TimeUnit.MILLISECONDS);//有限等待
        queue.offer("bb",30,TimeUnit.MILLISECONDS);
    }

5.线程池

当有大量线程时能以某种策略自动管理这些线程。

主要实现方式:

    @Test
    void ThreadPool(){
        ExecutorService executorService= Executors.newCachedThreadPool(); //选择一种线程池
        Runnable task1=()->{  //构造任务
            System.out.println("task1");
        };
        executorService.submit(task1); //加入线程池
        executorService.shutdown(); //关闭
    }

线程池类型

CachedThreadPool

特点:无核心线程,非核心线程数量无限,执行完闲置 60s 后回收,任务队列为不存储元素的阻塞队列。
应用场景:执行大量、耗时少的任务。

FixedThreadPool

特点:只有核心线程,线程数量固定,执行完立即回收,任务队列为链表结构的有界队列。
应用场景:控制线程最大并发数。

SingleThreadExecutor

特点:只有 1 个核心线程,无非核心线程,执行完立即回收,任务队列为链表结构的有界队列。
应用场景:不适合并发但可能引起 IO 阻塞性及影响 UI 线程响应的操作,如数据库操作、文件操作等

ScheduledThreadPool

特点:核心线程数量固定,非核心线程数量无限,执行完闲置 10ms 后回收,任务队列为延时阻塞队列。
应用场景:执行定时或周期性的任务。

参考

线程池的总结来源于Java 多线程:彻底搞懂线程池,讲的比较清晰

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值