并发编程.

1、概述

1.1 进程和线程

进程:操作系统资源分配的最小单位。

  • 程序由指令和数据组成,指令要执行,数据要读写,就必须将指令加载至cpu,数据加载至内存,在指令运行过程中还需要用到磁盘、网络等设备,进程就是用来加载指令、管理内存、管理io的。
  • 当一个程序被运行,从磁盘加载这个代码至内存,这时就开启了一个进程。

线程:处理器任务调度和执行的最小单位。

  • 一个进程之内可以分为一到多个线程
  • 一个线程就是一个指令流,将指令流中的指令以一定的顺序交给cpu执行

区别

  • 进程基本上相互独立,线程存在于进程内,是进程的一个子集
  • 进程拥有共享的资源,如内存空间等,供其内部的线程共享
  • 进程间的通信:同一台计算机的进程通信称为IPC,不同计算机之间的进程通信,需要通过网络,并遵守共同的协议,如HTTP协议
  • 线程间通信比较简单,因为他们共享进程内的内存
  • 线程更轻量,线程上下文切换成本一般比进程上下文切换低

1.2 并发和并行

  • 并发
    同一时间应对多件事情的能力

单核cpu下,线程实际还是串行执行的,任务调度器将cpu的时间片分给不同的线程使用,只是由于cpu在线程间的切换时间非常快,给人感觉同时运行,微观串行,宏观并行,cpu的这种做法称为并发

  • 并行
    同一时间处理多件事情的能力

1.3 应用

单核仍是串行,多核才有意义

  • 异步调用
  • 提高效率

2、线程

2.1 创建线程

  • 使用Thread
@Slf4j
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(){
            @Override
            public void run() {
                log.info("thread is run");
            }
        };
        thread.start();
    }
}
  • 使用Runnable
@Slf4j
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = ()-> log.info("thread is run");
        Thread thread = new Thread(runnable);
        thread.start();
    }
}
  • 使用Callable+FutureTask
@Slf4j
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        Callable<String> callable = () -> {
            log.info("thread is run");
            return "success";
        };
        FutureTask<String> futureTask = new FutureTask<>(callable);
        Thread thread = new Thread(futureTask);
        thread.start();
    }
}

2.2 查看线程

  • windows

任务管理器
tasklist 查看进程
taskkill 杀死进程

  • linux

ps -ef 查看所有进程
ps -fT -p 查看某个进程的所有线程
kill 杀死进程
top 按大写H切换是否显示线程
top -H -p 查看某个进程的所有线程

  • java

jps 查看所有java进程
jstack 查看进程的所有线程
jconsole

2.3 线程运行原理

  • 栈与栈帧
  • 每个栈由多个栈帧组成,对应着每次方法调用时所占的内存
    每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
  • 线程上下文切换
  • 线程的cpu时间片用完
    垃圾回收
    有更优先级的线程需要运行
    线程自己调用了sleep、yield、wait、join、park、synchronized、lock等方法
    当上下文切换时,由操作系统保存当前线程的状态,并恢复另一个线程的状态,java中对应的就是程序计数器,它的作用是记住下一条jvm指令的执行地址,它是线程私有的。

在这里插入图片描述

2.4 线程的使用

  • start & run
  • sleep & yeild
  • join
  • interrupt 打断
    打断sleep,wait,join的线程会抛出异常
@Slf4j
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        log.debug("enter main...");
        Thread t1 = new Thread(() -> {
            log.debug("t1 start...");
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    log.debug("t1 exit...");
                    break;
                }
            }
        });
        t1.start();
        Thread.sleep(1000);
        log.debug("t1 start interrupt...");
        t1.interrupt();
        log.debug("" + t1.isInterrupted());
        log.debug("exit main...");
    }
}
  • park
@Slf4j
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
       Thread t1 = new Thread(()->{
           log.debug("park...");
           LockSupport.park();
           log.debug("unpark...");
           log.debug("打断状态"+ Thread.interrupted());
           LockSupport.park();
           log.debug("unpark...");
       },"t1");
       t1.start();
       Thread.sleep(1000);
       t1.interrupt();
    }
}

2.5 守护线程

@Slf4j
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
       Thread t1 = new Thread(()->{
           while (true){
               if(Thread.interrupted()){
                   break;
               }
           }
           log.debug("t1 end");
       },"t1");
       t1.setDaemon(true);
       t1.start();
       Thread.sleep(1000);
       log.debug("main end");
    }
}

2.6 线程的状态

2.6.1 分类

  • 按操作系统分
    在这里插入图片描述
  • 按java api分
    在这里插入图片描述

2.7 应用

异步调用: 主线程执行期间,其他线程异步执行耗时操作
提高效率: 并行计算,缩短运算时间
同步等待:join
统筹规划:合理使用线程,得到最优效果

2.7.1 两阶段终止模式

@Slf4j
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        TwoPhaseTermination twoPhaseTermination = new TwoPhaseTermination();
        twoPhaseTermination.start();
        twoPhaseTermination.stop();
    }
}

@Slf4j(topic = "TwoPhaseTermination")
class TwoPhaseTermination {
    private Thread monitor;

    public void start() {
        monitor = new Thread(() -> {
            Thread current = Thread.currentThread();
            while (true){
                if(current.isInterrupted()){
                    log.debug("料理后事");
                    break;
                }

                try {
                    Thread.sleep(1000);
                    log.debug("执行监控记录");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    current.interrupt();
                }
            }
        });
        monitor.start();
    }

    public void stop() {
        monitor.interrupt();
    }
}

2.7.2 统筹规划

在这里插入图片描述

@Slf4j
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
       Thread t1 = new Thread(()->{
           try {
               log.debug("洗水壶");
               Thread.sleep(1);
               log.debug("烧开水");
               Thread.sleep(5);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }

       },"小王");

        Thread t2 = new Thread(()->{
            try {
                log.debug("洗茶壶");
                Thread.sleep(1);
                log.debug("洗茶杯");
                Thread.sleep(2);
                log.debug("拿茶叶");
                Thread.sleep(1);
                t1.join();
                log.debug("泡茶");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"小张");
        t1.start();
        t2.start();
    }
}

3、并发-共享内存模型

3.1 管程-悲观锁(阻塞)

3.1.1 共享带来的问题

  • 临界区:
    一段代码块如果存在对共享资源的多线程读写操作,成这段代码块为临界区。在这里插入图片描述
  • 竞态条件
    多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件

3.1.2 synchronized解决方案

  • 应用互斥
  • 阻塞式的解决方案:synchronized(俗称对象锁)、lock
  • 非阻塞式的解决方案:原子变量

synchronized实际是利用对象锁保证了临界区的原子性,临界区内的代码对外是不可分割的,不会被线程切换所打断

@Slf4j
public class Test01 {

    public static void main(String[] args) throws InterruptedException {
        LockTest lockTest = new LockTest();
       Thread t1 = new Thread(()->{
           for (int i = 0; i < 5000; i++) {
               lockTest.increment();
           }

       },"t1");

        Thread t2 = new Thread(()->{
            for (int i = 0; i < 5000; i++) {
                lockTest.decrement();
            }
        },"t2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(lockTest.get());
    }
}


class LockTest{
    private int count = 0;

    public void increment(){
        synchronized (this){
            count++;
        }
    }

    public void decrement(){
        synchronized (this){
            count--;
        }
    }

    public int get(){
        synchronized (this){
            return this.count;
        }
    }
}
  • 同步方法和静态同步方法的区别
    在这里插入图片描述

3.2 JMM

3.3 无锁-乐观锁(非阻塞)

3.4 不可变

3.5 并发工具

3.6 异步编程

4、并发-非共享模型

5、并行

6、应用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值