Java并发编程——概念

线程、异步和并发

  • 程序:为完成某个任务、用某种语言编写的一系列指令的集合,是静态的代码、静态的对象

  • 进程:程序执行的过程,即正在执行的程序,是动态的、有生命周期的

  • 线程:进程可进一步细分为线程,是程序内部的一条执行路径,如电脑管家杀毒、清理垃圾,就是两个

  • 单核CPU:只有一个CPU,在同一个时间片内,只执行一个线程。通过时间片轮转,在不同线程之间迅速地切换线程,让人能感觉在同时执行多个线程。

  • 多核CPU:在同一个时间片内,有多个CPU执行多个线程

  • 同步:调用方法返回结果后,才能继续后续的行为

  • 异步:调用方法立即返回,开始另一个方法,当真实的返回结果出现后会通知调用者。

同步就像线下购物,要先在商城选择商品,在收银台付账后自己把商品运回家。
异步就像线上购物,不需要到商城,在家里下单后自己就可以做别的事去了,由商家负责联系厂商,然后发货运到家。货运到家后,商家给你打电话,你就知

  • 并发:利用时间片轮转执行多个任务,即一个程序执行一段时间后,换另一个程序执行。
  • 并行:多个程序同时执行,只能在多核CPU中运行。

如果是多个线程都需要处理的数据,就放在临界区。每一次只能一个程序来使用,其他线程想要使用就必须等待。

并发问题

  • 阻塞:当一个线程处理一个数据时,在其释放资源之前,其他线程就会被挂起等待。是一种悲观策略,常用synchronized关键词。wait、join、yield、sleep方法都可以导致阻塞。
  • 非阻塞:当一个线程的执行不会阻碍其他线程的执行,发生冲突时,线程回滚。
  • 死锁(deadlock):当所有的线程都在处理同一个数据时,相互占用资源导致所有的线程都无法执行下去。就像道路上所有汽车占着别人的道,导致所有车辆都无法移动。
  • 饥饿(starvation):程序总是在执行级别高的线程,导致级别低的线程无法获得资源。
  • 活锁(livelock):多个线程处理同一个数据时,都主动释放资源给其他线程使用,导致没有一个线程能处理数据。就像迎面走来一个人,你们互相谦让,导致谁也无法前进。

并发级别

  • 阻塞
  • 无饥饿(starvation-free):使用非公平锁,级别高的线程就会插队;使用公平锁,无论级别高低,所有的线程都需要排队
  • 无障碍(obstruction-free):
    当一个线程进入临界区后,其他线程也可以进入
    是一种乐观策略,认为线程发生冲突的概率不大。
    各个线程一旦发生冲突,会回滚对自己做的修改。
    可能会发生所有线程一起回滚的情况,导致没有一个线程能走出临界区。
    这种策略通常需要使用一致性标记,在线程进入临界区前,会读取并保存这个标记,随后再次读取这个标记。如果标记没有被修改,那么标记一致,线程进入临界区,否则就表示有线程冲突,再重新操作。
  • 无锁(lock-free):
    所有线程都尝试访问临界区。
    如果有线程没有成功获取资源,就会继续尝试,直到成功为止。
    有可能出现修改不成功的线程无穷循环的情况,但能保证至少有一个线程可以走出临

并发编程特征

  • 原子性:即使多个线程一起执行,任一线程的操作都不会打断。
    *long型数据的读写不具有原子性

  • 可见性:如果一个线程修改了结果,那么其他线程都应该知道。

  • 有序性:保证写在前面的方法先执行,写在后面的后执行。
    *有时了优化CPU的操作,会进行指令重排,影响执行顺序。

Happen-Before原则

这是指令重排的原则

  • 程序顺序原则
  • volatile原则:volatile变量的写优先于读,保证可见性
  • 锁规则:同一把锁的解锁的操作要发生在下次加锁动作的前面
  • 传递性:A先于B,B先于C,那么A先于C
  • 线程的start()方法先于它的每一个操作
  • 线程的所有操作都先于它的终结
  • 线程的中断先于被中断线程的代码。
  • 对象的构造函数的执行、结束先于finalize()方法

线程生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aPFnQUgf-1605229416201)(http://note.youdao.com/yws/public/resource/5ab40ba87569962f76934bfd0001b7d4/xmlnote/9A1980E274904C02ACAB2DA27C135590/20361)]

线程优先级

从1到10,一般默认为5,优先级高更高的概率执行,但不一定就是先执行。
Thread类里有最大、最小和默认的常数优先级变量。

守护线程

类似于垃圾回收线程在Java中的作用,在start()方法之前使用setDaemo(),设置为true,否则就会变成用户线程。

举例:

class DaemonDemo extends Thread{
    @Override
    public void run(){
        while (true){
            System.out.println("I am alive");
            try {
                Thread.sleep(2000);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
   
    //调用守护线程
    public void test(){
        Thread t = new DaemonDemo();
        //设置为守护线程
        t.setDaemon(true);
        t.start();
    }

信号量

确定可以同时访问某个资源的线程的数量

举例:

class SemaphoreDemo implements Runnable{
    final Semaphore semaphore = new Semaphore(5);
    @Override
    public void run(){
        try {
            //尝试获取许可,如果无法获得,就会等待
            semaphore.acquire();
            //如果无法获得许可,立即返回false,不等待
            semaphore.tryAcquire();
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getId());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            semaphore.release();
        }

    }
}

倒计数器

规定数量的线程执行完后,再去执行主线程。
举例:

class CountDownLatchDemo implements Runnable{
    //10个线程倒数完后,才会执行主线程
    static final CountDownLatch end = new CountDownLatch(10);
    public static CountDownLatch getEnd() {
        return end;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(new Random().nextInt(10)*1000);
            System.out.println("check");
            //一个线程执行完后,倒计数器减一
            end.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

    public void test(){
        CountDownLatchDemo demo = new CountDownLatchDemo();
        ExecutorService exec = Executors.newFixedThreadPool(10);
        for (int i=0; i<10; i++){
            exec.submit(demo);
        }
        try {
            CountDownLatchDemo.getEnd().await();
            System.out.println("fire");
            exec.shutdown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

循环栅栏

相当于可重用的倒计数器

举例:

ier.await();
            doWork();
            barrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

    void doWork(){
        System.out.println(solider+":任务完成");
    }
}

class BarrierRun implements Runnable{
    boolean flag;
    int N;

    BarrierRun(boolean flag, int N){
        this.flag = flag;
        this.N = N;
    }

    @Override
    public void run() {
        if (flag){
            System.out.println("司令:士兵"+N+"个,任务完成!");
        }
        else{

            System.out.println("司令:士兵"+N+"个,集合完毕!");
            flag=true;
        }
    }
}

    public void test(){
        final int N=10;
        Thread[] allSolider = new Thread[N];
        boolean flag = false;
        CyclicBarrier barrier = new CyclicBarrier(N,new BarrierRun(flag, N));
        System.out.println("集合队伍");
        for (int i=0; i<N; ++i){
            System.out.println("士兵"+i+"报道");
            allSolider[i] = new Thread(new CyclicBarrierDemo(barrier,"士兵"+i));
            allSolider[i].start();
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值