zoukankan      html  css  js  c++  java
  • 线程问题

    线程的入门

    在了解线程之前,首先明白什么是进程。

    什么是进程:

    进程是指运行中的应用程序,每个进程都会有自己独立的地址空间(内存空间)比如:浏览器,编译器,系统任务管理器等等。操作系统会给该进程分配独立的地址空间,当用户再次点击浏览器时,就又启动一个进程。用户每启动一个进程,操作系统就会给该进程分配一个独立的内存空间。

    什么是线程:

    线程可以理解成进程的寄生,一个进程可以由多个线程。线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但他可与同属一个进程的其他线程共享所拥有的全部资源,一个线程可以创建和撤销另一个线程,线程可以并发执行。

    线程有三种基本状态:就绪,阻塞,运行。

    线程的理解:

    1、线程是轻量级进程。

    2、线程没有独立的地址空间

    3、线程由进程创建(寄生)

    4、一个进程可以拥有多个线程------>多线程

    5、线程的生命周期:

      新建状态,就绪状态,运行状态,阻塞状态,死亡状态。

    线程的应用场景:

    1、我们熟悉的Tomcat服务器内部就是使用多线程:

    上百个客户访问同一个web应用,Tomcat接入后都是把后续的处理扔给一个新的线程来处理,这个新的线程就是servlet程序,比如doGetdoPost

    如果不采用多线程,上百个用户同时访问一个web应用的时候,只能使用串行处理,那样就不实际。

    2、异步处理:

    异步处理也使用多线程,比如task a和task b要并行处理。但是CPU是多核的话,就可以让一个CPU执行有一个线程,如果只有一个CPU的话,底层是按照分时复用的原则,各个线程按照时间获取CPU资源。

    3、javaweb应用中很少用到多线程,因为在开发过程中,多线程被框架实现了,需要自己实现的很少。

    4、用的比较多的时网络应用程序。

    线程的安全问题:

    为什么又线程安全问题?

    当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。但是做读操作是不会发生数据冲突问题。

    经典案例就是抢火车票的案例啦:

    class ThreadTrain1 implements Runnable {

    private int count = 100;

    private static Object oj = new Object();

    @Override

    public void run() {

    while (count > 0) {

    try {

    Thread.sleep(50);

    } catch (Exception e) {

    // TODO: handle exception

    }

    sale();

    }

    }

    public void sale() {

    // 前提 多线程进行使用、多个线程只能拿到一把锁。

    // 保证只能让一个线程 在执行 缺点效率降低

    // synchronized (oj) {

    // if (count > 0) {

    System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - count + 1) + "");

    count--;

    // }

    // }

    }

    }

    public class ThreadDemo {

    public static void main(String[] args) {

    ThreadTrain1 threadTrain1 = new ThreadTrain1();

    Thread t1 = new Thread(threadTrain1, "①号窗口");

    Thread t2 = new Thread(threadTrain1, "②号窗口");

    t1.start();

    t2.start();

    }

    }

    运行结果:

    可以看到一号跟二号出现抢到同一张票,这显然是不可用的

    线程安全的解决办法:

    使用同步synchronized或者使用锁(lock)

    为什么使用多线程同步或者锁就能解决线程安全问题?

    答:因为多线程可能会发生数据冲突问题(线程不安全问题),只能让当前一个线程执行,同步/锁内的代码执行完之后,才能让其他线程进来执行,一个一个执行,这样就可以解决线程不安全问题。多个线程共享一个资源,不会收到其他线程的干扰。

    多线程同步代码块案例:

    private static Object oj = new Object();   

    public void sale() {

    // 前提 多线程进行使用、多个线程只能拿到一把锁。

    // 保证只能让一个线程 在执行 缺点效率降低

     synchronized (oj) {

    if (count > 0) {

    System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - count + 1) + "票");

    count--;

    }

     }

    }

    也可以这样写:

    public synchronized void sale() {

    if (trainCount > 0) { 

    try {

    Thread.sleep(40);

    } catch (Exception e) {

    }

    System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - trainCount + 1) + "张票.");

    trainCount--;

    }

    }

     注意:使用同步代码块的时候一般都是使用当前类。静态方法时使用锁时当前类的字节码文件。

    多线程死锁:

     简单理解:同步中嵌套同步,导致锁无法释放。

    class ThreadTrain6 implements Runnable {

    // 这是货票总票数,多个线程会同时共享资源

    private int trainCount = 100;

    public boolean flag = true;

    private Object mutex = new Object();

    @Override

    public void run() {

    if (flag) {

    while (true) {

    synchronized (mutex) {

    // 锁(同步代码块)在什么时候释放? 代码执行完, 自动释放锁.

    // 如果flag为true 先拿到 obj,在拿到this 锁、 才能执行。

    // 如果flag为false先拿到this,在拿到obj锁,才能执行。

    // 死锁解决办法:不要在同步中嵌套同步。

    sale();

    }

    }

    } else {

    while (true) {

    sale();

    }

    }

    }

    public synchronized void sale() {

    synchronized (mutex) {

    if (trainCount > 0) {

    try {

    Thread.sleep(40);

    } catch (Exception e) {

    }

    System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - trainCount + 1) + "张票.");

    trainCount--;

    }

    }

    }

    }

    public class DeadlockThread {

    public static void main(String[] args) throws InterruptedException {

    ThreadTrain6 threadTrain = new ThreadTrain6(); // 定义 一个实例

    Thread thread1 = new Thread(threadTrain, "一号窗口");

    Thread thread2 = new Thread(threadTrain, "二号窗口");

    thread1.start();

    Thread.sleep(40);

    threadTrain.flag = false;

    thread2.start();

    }

    }

    多线程的三大特性:

    1、原子性

    原子性是指不可分割,必须前后一致,比如去银行存取钱,A账户往B账户里转1000块钱,A账户里减去1000,B账户增加1000,前后不可以有分割。

    2、可见性

    多个线程访问同一个变量时,一个线程修改了该变量的值,其他线程能够立即看到修改的值

    3、有序性

     程序执行的顺序按照代码的先后顺序执行。

    Java内存模型:

    共享内存模型指的就是Java内存模型(简称JMM)JMM决定一个线程对共享变量的写入时,对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。

    解决问题= 态度(珍惜,无我(找不到我),空船) +归因(并不是所有的问题都需要解决,并不是所有问题都需要现在解决,并不是所有的问题都需要自己解决) +解决方法 (金字塔原理 (背景,结论,阐述支撑观点,对于观点(背景,结论,观点。。。)二叉树) +系统循环方法)
  • 相关阅读:
    Date类型 方法
    迭代方法和归并函数
    js快速排序方法
    reset
    水平垂直居中
    css清除浮动
    box-shadow
    display---我的第一篇博客
    centos7基础安装
    aws和ufile挂载数据盘EBS
  • 原文地址:https://www.cnblogs.com/InterfaceAOP/p/10223700.html
Copyright © 2011-2022 走看看