Android开发之路——多线程

作者: 程序老秃子 | 来源:发表于2022-04-11 16:02 被阅读0次

前言

Android多线程机制

我们一般将Android应用分成为两种:主线程和工作线程;主线程主要是用来进行初始化UI,而工作线程主要是进行耗时操作,例如读取数据库,网络连接等

Android系统是以进程为单位来对应用程序资源进行限制,这个问题的可以解释为:一个进程最多能够开几个线程?最好能开几个?但实则这个是没有上限这一说,主要是因为资源的限制

Android中关于主线程的理解:Android的主线程是UI线程,在Android中,四大组件运行在主线程中,在主线程中做耗时操作会导致程序出现卡顿甚至出现ANR异常,一个.

在一个程序中,这些独立运行的程序片断叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。多线程处理一个常见的例子就是用户界面。

多线程基础

线程总的来就是进程的一个实体,是CPU进行分派和调度的基本单位,拥有着比进程更小且能够独立运行的基本单位,线程本身基本上是不拥有系统资源,仅拥有一点在运行过程中必须拥有的资源,但它可与同属一个进程中的其他进程进行共享其所拥有的所有资源

线程状态

线程状态有些地方将之分为5中状态,而且在Java Jdk中线程被其定义为6中状态,我们可以对其进行类比

普遍定义的5中状态:新建,就绪,运行,阻塞, 死亡Java Jdk 定义状态

线程阻塞

线程阻塞是指在某一时刻的某一个线程在进行运行一段代码的情况下,突然另一个线程也要进行运行,但在运行过程中,那个线程执行完全运行之前,另一个线程是不可能获取到CPU的执行权,就会导致线路阻塞的出现

死锁

死锁也称之为抱死,意思就是说一个进程锁定了另外一个进程所需要的页或表是,但第二个进程同时又锁定了第一个进程所需的一页,这样就会出现死锁现象

使用代码实现死锁

public class DeadLock implements Runnable{

   private int flag;

   // 注意...  这里对象必须是static类型的,保证锁住的是同一个对象

   private static final Object object1 = new Object();

   private static final Object object2 = new Object();

   public DeadLock(int flag) {

       this.flag = flag;

   }

   @Override

   public void run(){

       if (flag == 1){

           synchronized (object1){

               System.out.println("持有对象object1的锁,等待持有object2锁释放资源");

               try {

                   Thread.sleep(2000);

               } catch (InterruptedException e) {

                   e.printStackTrace();

               }

               synchronized (object2){

                   System.out.println("程序结束");

               }

           }

       }

       if (flag == 2){

           synchronized (object2){

               System.out.println("持有对象object2的锁,等待持有object1锁释放资源");

               try {

                   Thread.sleep(2000);

               } catch (InterruptedException e) {

                   e.printStackTrace();

               }

               synchronized (object1){

                   System.out.println("程序结束");

               }

           }

       }

   }

}

public class Client {

   public static void main(String[] args){

       new Thread(new DeadLock(1)).start();

       new Thread(new DeadLock(2)).start();

       //持有对象object1的锁,等待持有object2锁释放资源

       //持有对象object2的锁,等待持有object1锁释放资源

       // .......程序一直运行.......

   }

}

线程使用

创建线程

简要的介绍一下实现线程的三种方式:继承Thread,实现runnable,实现callable。还有一点需要注意的是,实现callable是与线程池所相关联的而callable很重要的一个特性是其带有返回值。当我们只需实现单线程时实现runnable更加利于线程程序的拓展

public class HappyThread extends Thread {

   @Override

   public void run() {

       super.run();

       System.out.println("继承Thread");

   }

}

public class JobRunnable implements Runnable {

   @Override

   public void run() {

       try {

           Thread.sleep(1000);

           System.out.println("实现runnable实现线程");

       } catch (InterruptedException e) {

           e.printStackTrace();

       }

   }

}

public class EnjoyCallable implements Callable<String> {

   @Override

   public String call() throws Exception {

       Thread.sleep(2000);

       return "实现callable实现线程池";

   }

}

public class Client {

   public static void main(String[] args){

       // 继承thread实现线程

       new HappyThread().start();

       // runnable 与 线程

       new Thread(new JobRunnable()).start();

       // callable 与 线程池

       // 包含返回值

       ExecutorService executorService =  Executors.newCachedThreadPool();

       Future<String> submit = executorService.submit(new EnjoyCallable());

       try {

           System.out.println(submit.get());

           submit.cancel(true);

       } catch (InterruptedException e) {

           e.printStackTrace();

       } catch (ExecutionException e) {

           e.printStackTrace();

       }

   }

   //继承Thread

   // ** 1s后 **

   //实现runnable实现线程

   // ** 2秒后 **

   //实现callable实现线程池

}

守护线程

在线程开启之前进行调用 thread.setDaemon(true); 将thread设定成当前线程中的守护线程使用案例

public class DaemonThreadClient {

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

       Thread thread = new DaemonThread();

       thread.setDaemon(true);

       thread.start();

       Thread.sleep(20);

       System.out.println("主线程结束");

   }

}

class DaemonThread extends Thread{

   @Override

   public void run() {

       while (true){

           try {

               Thread.sleep(5);

               System.out.println("守护线程运行中");

           } catch (InterruptedException e) {

               e.printStackTrace();

           }

       }

   }

}

//output

//守护线程运行中

//守护线程运行中

//守护线程运行中

//守护线程运行中

//主线程结束

//Process finished with exit code 0

yield线程让步与join合并等待线程结束

线程让步【yield方法】让当前线程释放CPU资源,让其他线程抢占

public class YieldClient {

   public static void main(String[] args){

       new ThreadA().start();

       new ThreadB().start();

   }

}

class ThreadA extends Thread{

   public ThreadA(){

       setPriority(2);

   }

   @Override

   public void run() {

      yield();

      for (int i=0;i<10;i++){

          System.out.println("ThreadA 低优先级的运行");

      }

   }

}

class ThreadB extends Thread{

   public ThreadB(){

       setPriority(8);

   }

   @Override

   public void run() {

       for (int i=0;i<10;i++){

           System.out.println("ThreadB 高优先级的运行");

       }

   }

}

//  output

//    ThreadB 高优先级的运行

//    ...

//    ThreadB 高优先级的运行

//    ThreadA 低优先级的运行

//    ThreadA 低优先级的运行

//    ThreadA 低优先级的运行

//    ThreadA 低优先级的运行

//    ...

//    ThreadA 低优先级的运行

//    ThreadA 低优先级的运行

//    Process finished with exit code 0

线程阻塞等待但不会释放锁资源

public class JoinClient {

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

       JoinAThread joinAThread = new JoinAThread();

       joinAThread.start();

       joinAThread.join();

       System.out.println("主线程 开始");

       Thread.sleep(10);

       System.out.println("主线程 运行中");

       Thread.sleep(10);

       System.out.println("主线程 运行中");

       System.out.println("主线程 结束");

   }

}

class JoinAThread extends Thread{

   @Override

   public void run() {

       super.run();

       try {

           System.out.println("JoinAThread 开始");

           Thread.sleep(30);

           System.out.println("JoinAThread 运行中");

           Thread.sleep(30);

           System.out.println("JoinAThread 运行中");

           System.out.println("JoinAThread 结束");

       } catch (InterruptedException e) {

           e.printStackTrace();

       }

   }

}

//output

//JoinAThread 开始

//JoinAThread 运行中

//JoinAThread 运行中

//JoinAThread 结束

//主线程 开始

//主线程 运行中

//主线程 运行中

//主线程 结束

//

//Process finished with exit code 0

线程终止

public class InterruptClient {

   public static void main(String[] args){

       new InterruptThread().start();

   }

}

class InterruptThread extends Thread{

   @Override

   public void run() {

       super.run();

       for (int i=0;i<10;i++){

           if (isInterrupted()){

               System.out.println("线程打断而结束");

               return;

           }

           System.out.println("线程执行..."+i);

           if (i == 2){

               // 终止线程

               interrupt();

           }

       }

   }

}

//output

//线程执行...0

//线程执行...1

//线程执行...2

//线程打断而结束

//

//Process finished with exit code 0

线程关键知识点

Java中的sleep与wait区别

/**

* 测试 sleep 和 wait 区别

*/

public class Client {

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

       Product product = new Product();

       new Thread(new ChildSetRunnable(product),"set thread").start();

       // 主线程睡眠,保证获取线程晚于设置线程的执行

       Thread.sleep(500);

       new Thread(new ChildGetRunnable(product),"get thread").start();

   }

}

public class ChildGetRunnable implements Runnable {

   private Product product;

   public ChildGetRunnable(Product product) {

       this.product = product;

   }

   @Override

   public void run() {

       // 运行加锁

       System.out.println(Thread.currentThread().getName()+" run()");

       synchronized (product){

           System.out.println(Thread.currentThread().getName()+" "+System.currentTimeMillis()+" 读取价格 = "+product.getPrice());

       }

   }

}

public class ChildSetRunnable implements Runnable {

   private Product product;

   public ChildSetRunnable(Product product) {

       this.product = product;

   }

   @Override

   public void run() {

       System.out.println(Thread.currentThread().getName()+" run()");

       synchronized (product){

           try {

               System.out.println(Thread.currentThread().getName()+" "+System.currentTimeMillis()+" 设置价格= 100 开始");

               /**

                * 1.测试sleep 释放CPU时间片,但仍然持有对product的锁资源

                */

               Thread.sleep(3000);

               /**

                * 2.测试wait 释放CPU时间片,但是会释放锁资源

                */

               //product.wait(3000);

               product.setPrice("100");

               System.out.println(Thread.currentThread().getName()+" "+System.currentTimeMillis()+" 设置价格= 100 结束");

           } catch (InterruptedException e) {

               e.printStackTrace();

           }

       }

   }

}

这种具体某个对象锁 wait & notify 方法与Condition 的 await以及signal方法类似;全面这种方法的阻塞等待都可以是释放锁,而且在唤醒后,这种线程都是能够获取锁资源的,而这个门栓就跟阀门类似

结语

今天的课程就到这里了,有需要文章中所涉及到的源码可以点击下方评论区留言或者点击我的头像私信我

相关文章

网友评论

    本文标题:Android开发之路——多线程

    本文链接:https://www.haomeiwen.com/subject/ahoisrtx.html