详解Javase 多线程:彻底搞懂线程(下)

简介: Javase 详解 多线程:彻底搞懂线程

4.线程安全问题(重点:⭐⭐⭐⭐⭐)

4.1为什么这个是重点?

后在开发中,我们的项目都是运行在服务器当中,而服务器已经将线程的定义,线程对象的创建,线程的启动等,都 已经实现了。这些代码我们都不需要编写。

最重要的是:你要知道,你编写的程序需要放到一个多线程的环境下运行,你更需要关注的是这些数据再多线程并发的环境下是否是安全的。

4.2.什么情况下数据在多线程并发的情况下,存在线程安全问题

三个条件:

  • 条件1:多线程并发。
  • 条件2:有共享数据。
  • 条件3:共享数据有修改的行为。15.png

4.3.怎么解决线程安全问题呢?

当多线程并发的情况下,有共享数据,并且这个数据还会被修改,此时就存在线程安全问题,怎么解决这个问题?

线程同步机制

  • 线程排队执行(不能并发)。
  • 用排队执行解决线程安全问题。
  • 这种机制被称为:线程同步机制

怎末解决线程安全问题呀?

  • 使用“线程同步机制”

线程同步就是线程排队了,县城排队了就会牺牲一部分效率,没办法,数据安全第一位,只有数据安全了,我们才可以谈效率。数据不安全,没有效率的事儿。

4.4.线程同步,两个专业术语

1、异步编程模型:

  • 线程t1和线程t2,各自执行各自的,t1不管t2,t2不管t1,谁也不需要等谁,这种编程模型叫做:异步编程模型。其实就是:多线程并发(效率更高。)
  • 异步就是并发。

2、同步编程模型:

  • 线程t1和线程t2,在线程t1执行的时候,必须等待t2线程执行结束,或者或在t2线程执行的时候,必须等待t1线程执行结束,两个线程之间发生了等待关系,这就是同步编程模型。效率较低。线程排队执行。
  • 同步就是排队。

4.5模拟线程安全问题。

4.5.1编写程序模拟两个线程同时对同一个账户进行取款操作。

账户类

package com.newXianCheng.ThreadSafe;
/**
 * @Description: 银行账户类   
 * @auther:Li Ya Hui
 * @Time:2021年5月14日上午9:25:19
 */
public class Account {
  //账号
  private String actno;
  //余额
  private double balance;
  //无参
  public Account() {
  }
  //有参
  public Account(String actno, double balance) {
    this.actno = actno;
    this.balance = balance;
  }
  //方法
  public String getActno() {
    return actno;
  }
  public void setActno(String actno) {
    this.actno = actno;
  }
  public double getBalance() {
    return balance;
  }
  public void setBalance(double balance) {
    this.balance = balance;
  }
  //取款
  public void withdarw(double money) 
  {
    //取款之前的余额
    double before = this.getBalance();
    //取款之后的余额
    double after = before-money;
    //模拟网络延迟  一定出问题
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    //更新余额
    this.setBalance(after);
  }
}

取款的线程

package com.newXianCheng.ThreadSafe;
/**
 * @Description: 取款的线程
 * @auther:Li Ya Hui
 * @Time:2021年5月14日上午10:54:38
 */
public class AccountThread extends Thread{
  //两个线程必须共享同一个账户对象。
  private Account act ;
  //通过构造方法传递过来账户对象
  public AccountThread(Account act) {
    super();
    this.act = act;
  }
  @Override
  public void run() {
    //run方法的执行表示取款操作
    double money = 5000;
    //取款
    //多线程并发执行这个方法
    act.withdarw(money);
    System.out.println("账户"+act.getActno()+"取款成功,余额"+act.getBalance());
  }
}

取款的测试类

package com.newXianCheng.ThreadSafe;
/**
 * @Description: 测试类  测试取款操作
 * @auther:Li Ya Hui
 * @Time:2021年5月14日上午10:20:50
 */
public class Test {
  public static void main(String[] args) {
    Account act = new Account("act-001",20000);
    AccountThread t1 = new AccountThread(act);
    AccountThread t2 = new AccountThread(act);
    //设置name
    t1.setName("t1");
    t2.setName("t2");
    //启动线程取款
    t1.start();
    t2.start();
  }
}

输出结果:出现问题

账户act-001取款成功,余额15000.0账户act-001取款成功,余额15000.0
4.5.2.同步代码块synchronized

线程同步机制的语法是:

  • synchronized后面小括号中传的这个“数据”是相当关键的。
  • 这个数据必须是多线程共享的数据。才能达到多线程排队。
  • ()中写什么?
  • 需要看你想让那些线程同步。
  • 假设t1,t2,t3,t4,t5 5个线程
  • 你只希望t1,t2,t3排队,t4,t5不需要排队,怎么办?
  • 你一定要在()中写一个t1,t2,t3共享的对象。而这个对象对于t4,t5来说,不是共享的。
synchronized(){ //线程同步代码块}

这里共享的对象是:账户对象。


账户对象是共享的,那么this就是账户对象!


不一定是this,这里只要是多线程共享的那个对象就行


在Java语言中,任何一个对象都有‘一把锁’,其实这把锁就是标记。(只是把它叫做锁)


100个对象,100把锁


以下代码的执行原理:


  • 假设t1和t2线程并发,开始执行以下代码的时候,肯定有一个先,一个后。
  • 假设t1先执行了,遇到了synchronized,这个时候自动找”后面共享对象“的对象锁,找到之后,并占有这把锁,然后执行同步代码块结束,这把锁才会释放。
  • 假设t1已经占有这把锁,此时t2也遇到synchronized关键字,也会去占有后面共享对象的这把锁,结果这把锁被t1占有,t2只能在同步代码块外面等待t1的结束,直到t1把同步代码块执行结束了,t1会归还这把锁,此时,t2终于等到这把锁,然后t2占有这把锁之后,进入同步代码块执行程序。
  • 这样就达到了线程排队执行
  • 这里需要注意的:这个共享对象一定要选好了。这个共享对象一定是你需要排队执行的线程对象所共享的
    //取款
  public void withdarw(double money) 
  {
    //以下几行代码必须是线程排队的,不能并发。
    //一个线程把这里的代码全部执行结束之后,另一个线程才能进来
    /*
     *线程同步机制的语法是:
      synchronized()
      {
        //线程同步代码块
      }
     */ 
    synchronized (this) {
      double before = this.getBalance();
      double after = before-money;
      //模拟网络延迟  一定出问题
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      //更新余额
      this.setBalance(after);
    }
  }

4.5.2.1对synchronized的理解16.png

4.5.2.2.Java中有三大变量(线程安全问题)?

  • 实例变量:在堆中。
  • 静态变量:在方法区中。
  • 局部变量:在栈中。

以上三大变量中:


局部变量永远都不会存在线程安全问题。


因为局部变量不共享。(一个线程一个栈)


局部变量在栈中。所以局部变量永远都不会共享。


实例变量在堆中,堆只有一个。


静态变量在方法区中,方法去只有一个。


堆和方法都是多线程共享的,所以可能存在线程安全问题。


局部变量+常量:不会有线程安全问题。


成员变量:可能会有线程安全问题。


4.5.2.3在实例方法上可以使用synchronized吗?可以的

  • synchronized出现在实例方法上,一定锁的是this。没得挑。只能是this。不能是其他的对象了。所以这种方式不灵活。
  • 另外还有一个缺点:synchronized出现在实例方法上,表示整个方法体都需要同步,可能会无故扩大同步的范围,导致程序员的执行效率降低。所以这种方式不常用。
  • synchronized使用在实例方法上有什么优点? 代码写得少了,节鉴了。
  • 如果共享的对象就是this,并且需要同步的代码块是整个方法体, 建议使用这种方式。

4.2.4.如果使用局部变量的话:


建议使用:StringBuilder。


因为局部变量不存在线程安全问题。选择stringBuilder.


StringBuffer效率比较低。


  • ArratList是非线程安全的。
  • Vector是线程安全的。
  • HashMap HashSet是非线程安全的。
  • Hashtable是线程安全的。

4.5.3.synchronized总结

synchronized有两种写法:


  • 第一种:同步代码块 灵活
synchronized(线程共享对象){ 同步代码块;}
  • 第二种:在实例方法上使用synchronized

表示共享对象一定是this

并且同步代码块是整个方法体。

  • 第三种:在静态方法上使用synchronized 表示找类锁。

类锁永远只有1把。

就创建了100个对象,那类锁也只有一把。

  • 对象锁:1个对象1把锁,100个对象100把锁。
  • 类锁:100个对象,也可能只是1把类锁。


4.5.4.synchronized面试题

package com.newXianCheng.ThreadSafe3;
/**
 * 
 * @Description: synchronized 面试题: 第二个线程是否运行的方法是否会
 * @auther:Li Ya Hui
 * @Time:2021年5月16日上午10:46:12
 */
//测试类
public class Exam {
  public static void main(String[] args) {
    System.out.println(~-12);
    System.out.println(~12);
    MyClass mc = new MyClass();
    MyThread t1 = new MyThread(mc);
    MyThread t2 = new MyThread(mc);
    t1.setName("t1");
    t2.setName("t2");
    t1.start();
    try {
      Thread.sleep(1000);//保证t1线程先执行
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    t2.start();
  }
}
//线程类
class MyThread extends Thread
{
  private MyClass mClass ; 
  public MyThread(MyClass myClass) {
    this.mClass = myClass;
  }
  public void run() 
  {
    if(Thread.currentThread().getName().equals("t1")) 
    {
      mClass.doSome();
    }else if(Thread.currentThread().getName().equals("t2")) 
    {
      mClass.doOther();
    }
  }
}
//我的任务类
class MyClass {
  public synchronized void doSome()
  {
    System.out.println("doSome begin");
    try {
      Thread.sleep(1000*3);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("doSome over");
  }
  public  void doOther() {
    System.out.println("doOther begin");
    System.out.println("doOther over");
  }
}
  • 判断t2线程是否会等待t1线程结束
  • 结果证明,当一个方法锁住当前对象时,有线程去运行时,其他没有锁的方法在别的线程去运行时并不会等待前一个线程
4.5.5.死锁演示
package com.newXianCheng.ThreadSafe3.DeadLock;
/**
 * @Description:
 *        死锁代码要会写
 *        一般面试官要求你写。
 *        只有会写的,才会在以后的开发中注意这个事儿。
 *        因为死锁很难调试
 * @auther:Li Ya Hui
 * @Time:2021年5月16日下午6:55:47
 */
public class DeadLock {
  public static void main(String args[]) 
  {
    Object o1 = new Object();
    Object o2 = new Object();
    Thread t1 = new MyThread1(o1, o2);
    Thread t2 = new MyThread2(o1, o2);
    t1.start();
    t2.start();
  }
}
/**
 * @Description: 死锁演示
 * @auther:Li Ya Hui
 * @Time:2021年5月16日下午6:58:42
 */
class MyThread1 extends Thread{
  Object o1 ;
  Object o2 ;
  public MyThread1(Object o1 , Object o2){
    this.o1 = o1 ;
    this.o2 = o2;
  }
  public void run() 
  {
    synchronized (o2) {
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      synchronized (o1) {
        System.out.println("1");
      }
    }
  }
}
class MyThread2 extends Thread{
  Object o1 ;
  Object o2 ;
  public MyThread2(Object o1 , Object o2){
    this.o1 = o1 ;
    this.o2 = o2;
  }
  public void run() 
  {
    synchronized (o1) {
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      synchronized (o2) {
        System.out.println("2");
      }
    }
  }
}

4.5.6.开发中怎么解决线程安全问题

聊一聊,我们以后开发中应该怎么解决线程安全问题?


  • 是一上来就选择线程同步吗?synchronized
  • 不是,synchronized会让程序的执行效率降低,用户体验不好。
  • 系统的用户吞吐量降低。用户体验极差。在不得已的情况下在选择线程同步机制。

第一种方案:尽量使用局部变量代替“实例变量和静态变量”。


第二种方案:如果必须是实例变量,那么可以考虑创建多个对象,这样实例变量的内存就不共享了。(一个线程对应1个对象,100个线程对应100个对象,对象不共享,就没有数据安全问题了。)


第三种方案:如果不能使用局部变量,对象也不能创建多个,这个时候就只能synchronized了。线程同步机制。

5.线程剩余内容(难度:⭐⭐⭐)

5.1.守护线程

Java语言中线程分为两大类:

  • 一类是:用户线程
  • 一类是:守护线程(后台线程)
  • 其中具有代表性的是:垃圾回收线程(守护线程)。

守护线程的特点:

  • 一般守护线程是一个死循环,所有的用户线程只要结束,守护线程自动结束。

注意:主线程main方法是一个用户线程

守护线程用在什么地方呢?

  • 每天00:00的时候系统数据自动备份。
  • 这个需要使用到定时器,并且我们可以将定时器设置为守护线程。
  • 一直在那里看着,每到00:00的时候就备份一次。所有的用户线程如果结束了,守护线程自动退出,没有必要进行数据备份了。

设置守护线程的语法

  • Thread.setDaemon(true);
package com.newXianCheng.ThreadShouHU;
/**
 * @Description: 守护线程
 * @auther:Li Ya Hui
 * @Time:2021年5月16日下午9:29:31
 */
public class Test01 {
  public static void main(String[] args) {
    Thread t2 = new bakDatathread();
    t2.start();
    Thread t = new bakDatathread();
    t.setName("备份数据的线程");
    //设置守护线程
    //启动线程之前,将线程设置为守护线程
    t.setDaemon(true);
    t.start();
    //主线程 : 主线程是用户线程
    for (int i = 0; i < 2; i++) {
      System.out.println(Thread.currentThread().getName()+"-->"+i);
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }
}
class bakDatathread extends Thread{
  public void run() {
    int i = 0;
    //即使是死循环,但由于该线程是守护者,当用户线程结束后,守护线程自动终止。
    while(true) 
    {
      System.out.println(Thread.currentThread().getName()+"  --  "+(++i));
      try {
        Thread.sleep(1999);
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }
}

需要注意的一些知识点:

  • 守护线程–也称“服务线程”,在没有用户线程可服务时会自动离开。
  • 守护线程就是运行在系统后台的线程,如果JVM中只有守护线程,则JVM退出。
  • Main主线程结束了(Non-daemon thread), 如果此时正在运行的其他threads是daemon threads , JVM会使得这个threads停止 , JVM也停下 , 如果此时正在运行的其他threads有Non-daemon threads,那么必须等所有的Non daemon线程结束了,JVM才会停下来。
  • 必须等所有的Non-daemon线程都运行结束了,只剩下daemon的时候,JVM才会停下来,注意Main主程序是Non-daemon线程.
  • 线程划分为用户线程和后台(daemon)进程,setDaemon将线程设置为后台进程
  • 典型的守护线程例子是JVM中的系统资源自动回收线程, 我们所熟悉的Java垃圾回收线程就是一个典型的守护线程。
  • setDarmon()方法在start()方法之前。
  • setDaemon方法把java的线程设置为守护线程,此方法的调用必须在线程启动之前执行。

5.2.定时器

定时器的作用

  • 间隔特定的时间,执行特定的程序。
  • 每周要进行银行账户的总帐操作。
  • 每天要进行数据的备份操作。
  • 在实际开发中,每隔多久执行一段特定的程序,这种需求是很常见的,那么在Java中其实可以采用很多中方式实现:
  1. 可以使用sleep方法,睡眠,设置睡眠时间,每到这个时间点醒来,执行任务。这种方式是最原始的定时器。(比较low)
  2. 在Java的类库中已经写好了一个定时器:java.util.Timer,可以直接拿来用。不过,这种方式在目前的开发中很少用,因为现在有很多高级框架都是支持定时任务的。
  3. 在实际的开发当中,目前使用较多的是spring框架中提供的springTask框架,这个框架只要进行简单的配置,就可以完成定时器的任务。

5.3.实现线程的第三种方式:FutureTask方式,实现Callable接口。(JDK8新特性)

  • 这种方式实现的线程可以获取线程的返回值。
  • 之前讲解的那两种方式是无法获取线程的返回值的,因为run方法返回void。


思考:


  • 系统委派一个线程去执行一个任务,该线程执行完任务之后,可能会有一个执行结果,我们怎么能拿到这个执行结果呢?
  • 使用第三种方式:实现Callable接口方式。

语法

package com.newXianCheng.CallableTest;
/**
 * @Description: 实现线程的第三种方式:
 *          实现Callable接口
 *          这种方式的优点:可以获取到线程的执行结果。
 *          这种方式的缺点:效率比较低,在获取t线程的时候,当前线程受阻塞,效率较低。
 * @auther:Li Ya Hui
 * @Time:2021年5月19日上午11:13:56
 */
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableTest01 {
  public static void main(String[] args) throws InterruptedException, ExecutionException {
    //第一步,创建一个“未来任务类”对象。
    //参数非常重要:效率比较低,在获取t线程的时候,当前线程受阻塞,效率较低。
    FutureTask task = new FutureTask(new Callable() {
      @Override
      public Object call() throws Exception {
        //线程执行一个任务 , 执行之后可能会有一个执行结果
        //模拟执行
        System.out.println("call method begin");
        Thread.sleep(1000*3);
        System.out.println("call method end");
        int a=100;
        int b=100;
        return a+b; // (自动装箱 integer)
      }
    });
    //创建线程对象
    Thread t  =new Thread(task);
    //启动线程
    t.start();
    //现在是main方法,主线程中
    //在主线程中,怎么获取t线程的返回结果?
    System.out.println(task.get());
    //main方法这里的程序要想执行必须等待get方法的结束
    //而get()方法可能需要很久。因为get方法是为了那另一个线程的执行结果
    //另一个线程执行是需要时间的。
  }
}
5.3.1.关于分支栈开启Callable会不会造成main栈堵塞的问题17.png
  • 回答:不会,c1线程的get方法只会对t1线程造成堵塞,不会对main方法造成影响

5.4.关于Object类中的wait方法和notify方法。(生产者和消费者模式!)

wait和notify方法不是线程对象的方法,是Java中任何一个Java对象都有的方法,因为这两个方式是object类中自带的。

  • wait方法和notify方法不是通过线程对象调用的,
  • 不是这样的:t.wait(),也不是这样的:t.notify()…不对。

wait方法的作用?

  • Object o = new Object();
  • o.wait();
  • 表示:
  • 让正在o对象上活动的线程进入等待状态,无限期待等待,直到唤醒为止
  • o.wait;方法的调用,会让“当前线程(正在o对象上活动的线程)”进入等待状态。

notify()方法作用?

  • Object o = new Object();
  • o.notify();
  • 表示:
  • 唤醒正在o对象上等待的线程。
  • 还有一个notifyAll()方法:
  • 这个方法是唤醒o对象上处于等待的所有线程。

重点:

  • o.wait()方法会让正在o对象上活动的当前线程进入等待状态,并且释放之前占有的o对象的锁。
  • o.notify()方法只会通知,不会释放之前占有的o对象的锁。


生产者和消费者 是为了专门解决某个特定需求的。

  • 一个线程负责生产 、 一个线程负责消费
  • 最终要达到生产和消费必须均衡。
  • 例如:
  • 生产满了,就不能再继续生产了,必须让消费线程进行消费。
  • 消费完了,就不能再消费了,必须让生产线程进行生产。
  • 仓库是多线程共享,所以需要考虑仓库的线程安全问题。
  • 仓库对象最终调用wait()和notify()方法。
  • wait()和notify()建立在synchronized线程同步的基础之上。
  • 代码
package com.newXianCheng.producer;
import java.util.ArrayList;
import java.util.List;
/**
 * @Description:
 * 1.使用wait方法和notify方法实现“生产者和消费者模式”
 * 2.什么是“生产者和消费者模式”?
 *    生产者负责生产,消费线程负责消费。
 *    生产线程和消费线程要达到均衡。
 *    这是一种特殊的业务需求,在这种特殊的情况下需要使用wait方法和notify方法。
 * 3.wait和notify方法不是线程对象的方法,是普通Java对象都有的方法。
 * 4.wait方法和nitify方法建立在线程同步的基础之上。因为多线程要同时操作一个仓库,有线程安全问题。
 * 5.wait方法作用:o.wait()让正在o对象上活动的线程t进入等待状态,并且释放掉t线程之前占有的o对象的锁。
 * 6.notify方法作用:o.notify()让正在o对象上等待的线程唤醒,只是通知,不会释放o对象上之前占有的锁
 * 7.模拟这样一个需求:
 *    仓库我们采用List集合。
 *    List集合中假设只能存储1个元素。
 *    1个元素就表示仓库满了。
 *    如果List中元素个数是0,就表示仓库空了。
 *    保证List中永远都是最多存储1个元素。
 *    
 * @auther:Li Ya Hui
 * @Time:2021年5月19日下午8:30:34
 */
public class Test {
  public static void main(String[] args) {
    //创建仓库对象
    List list = new ArrayList();
    //创建两个线程对象
    //生产者线程
    Thread t1 = new Thread(new Producer(list));
    //消费者线程
    Thread t2 = new Thread(new Consumer (list));
    t1.setName("生产者线程");
    t2.setName("消费者线程");
    t1.start();
    t2.start();
  }
}
//生产线程
class Producer implements Runnable{
  //仓库
  private List list ;
  public  Producer(List list) {
    this.list = list ;
  }
  @Override
  public void run() {
    //一直生产(使用死循环模拟一直生产)
    while (true) {
      //给仓库list加锁
      synchronized (list) {
        if (list.size()>0) {
          //当前线程进入等待状态,并且释放List集合的锁
          try {
            list.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          } 
        }
        //程序能够执行到这里说明仓库是空的,可以生产
        Object obj = new Object();
        list.add(obj);
        System.out.println(Thread.currentThread().getName() + "--->" + obj);
        //唤醒消费者,进行消费
        list.notify();
      }
    }
  }
}
//消费线程
class Consumer implements Runnable{
  //仓库
  private List list ;
  public  Consumer(List list) {
    this.list = list ;
  }
  @Override
  public void run() {
    //一直消费  
    while (true) {
      synchronized (list) {
        if (list.size() == 0) {
          try {
            //仓库空了,消费者线程等待, 释放掉List集合的锁
            list.wait();
          } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        }
        //程序执行到此处说明仓库中有数据,进行消费。
        Object obj = list.remove(0);
        System.out.println(Thread.currentThread().getName() + "--->" + obj);
        //唤醒生产者,进行生产
        list.notify();
      }
    }
  }
}
目录
相关文章
|
3天前
|
Java 数据库
【Java多线程】对线程池的理解并模拟实现线程池
【Java多线程】对线程池的理解并模拟实现线程池
11 1
|
3天前
|
设计模式 消息中间件 安全
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
9 0
|
3天前
|
Java
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
11 1
|
3天前
|
存储 缓存 安全
【Java多线程】线程安全问题与解决方案
【Java多线程】线程安全问题与解决方案
10 1
|
3天前
|
Java 调度
【Java多线程】线程中几个常见的属性以及状态
【Java多线程】线程中几个常见的属性以及状态
8 0
|
3天前
|
Java 调度
【Java多线程】对进程与线程的理解
【Java多线程】对进程与线程的理解
11 1
|
4天前
|
存储 安全 Java
【探索Linux】P.21(多线程 | 线程同步 | 条件变量 | 线程安全)
【探索Linux】P.21(多线程 | 线程同步 | 条件变量 | 线程安全)
10 0
|
14天前
|
Java 数据库 Android开发
【专栏】Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理
【4月更文挑战第27天】本文探讨了Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理。通过案例分析展示了网络请求、图像处理和数据库操作的优化实践。同时,文章指出并发编程的挑战,如性能评估、调试及兼容性问题,并强调了多线程优化对提升应用性能的重要性。开发者应持续学习和探索新的优化策略,以适应移动应用市场的竞争需求。
|
4天前
|
算法 安全 Linux
【探索Linux】P.20(多线程 | 线程互斥 | 互斥锁 | 死锁 | 资源饥饿)
【探索Linux】P.20(多线程 | 线程互斥 | 互斥锁 | 死锁 | 资源饥饿)
11 0
|
4天前
|
存储 安全 Linux
【探索Linux】P.19(多线程 | 线程的概念 | 线程控制 | 分离线程)
【探索Linux】P.19(多线程 | 线程的概念 | 线程控制 | 分离线程)
7 0