前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java多线程-完成Android开发中的某些需求

Java多线程-完成Android开发中的某些需求

作者头像
用户6256742
发布2024-05-17 09:38:04
860
发布2024-05-17 09:38:04
举报
文章被收录于专栏:网络日志网络日志
一 需求

子线程中开启一个主线程去获取某些数据,此时子线程要处理等待状态,获取成功之后继续执行子线程中之后的代码.

问题:当开启主线程去获取数据的时候,子线程的代码也会顺序去执行,这样并不能等到主线程有结果的时候再去执行子线程中的代码.

分析:先来分析一下,当在线程A中开启另外一个线程B的时候,线程A中的代码还是顺序执行线程B的代码也会执行.这样的话线程A中需要线程B中返回参数的方法就没办法正确执行.

解决:这里就用到了线程的wiat() notify() 和 synchronized 关键字,先来看下解决方法.

代码语言:javascript
复制
final  Object obj = new Object();
     new Thread(){
          @Override
          public void run() {
              super.run();
              //通过Handler创建一个主线程.
              new Handler(getMainLooper()).post(new Runnable() {
                  @Override
                  public void run() {
                      synchronized (obj) {
                      //模拟主线程耗时操作
                          try {
                              Thread.sleep(1000);
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                          str = "WangChao";
                          Log.e("CHAO", "run 2" + str);
                          obj.notify();
                      }
                  }
              });
              Log.e("CHAO","run 1");
              synchronized (obj) {
                  try {
                      obj.wait();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  //子线程需要主线程的返回参数
                  if (str != null) {
                      Log.e("CHAO", "run 3" + str);
                  }
              }
          }
      }.start();

运行可知先运行的是run 1 ,之后是主线程中的run 2 ,然后是子线程中的 run 3.这样就可以达到我们想要的结果.运行结果如下:

代码语言:javascript
复制
com.example.wang.threaddemo E/CHAO: run 1
com.example.wang.threaddemo E/CHAO: run 2WangChao
com.example.wang.threaddemo E/CHAO: run 3WangChao

二 涉及的Java线程的知识点

synchronized关键字的用法被synchronized修饰的方法称为同步方法,默认的锁是当前对象.所谓同步方法是如果有一个线程正在访问该方法的时候,其他的方法调用到该方法的时候将进入等待的状态.当有多个同步方法的时候,一旦一个线程调用了其中的一个同步方法,便对当前对象加锁,其他的线程调用拥有同对象锁的其它同步方法时会处于等待的状态,等之前的线程释放掉对象锁之后继续执行.1.去修饰方法 : 对象锁默认是当前对象 this .

代码语言:javascript
复制
public synchronized void method2(){
          Log.e("CHAO", "method2: " + Thread.currentThread().getName());
  }

还可以这样写:

代码语言:javascript
复制
       public  void method2(){
              synchronized (this) {
                  Log.e("CHAO", "method2: " + Thread.currentThread().getName());
              }
          }

2.同步语句块 : 可以自己去设置加锁的对象.

代码语言:javascript
复制
    synchronized (obj) {
                          try {
                              Thread.sleep(1000);
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                          str = "WangChao";
                          Log.e("CHAO", "2" + str);
                          obj.notify();
                      }

这里需要注意的是synchronized (obj) 里面的参数,也就是要给那个对象加锁.这个对象必须是唯一的切多个线程都能拿到这个对象.(再使用Stirng最为对象锁的时候一定要注意String的重新赋值,一旦赋值改对象就改变了不再是我们之前加锁的对象),通常可以自己去创建一个final 的 Object类去加锁,也可以使用this,Class对象等.

3.同步静态方法啊: 加锁对象是当前的Class对象.

代码语言:javascript
复制
public static synchronized void method1(){
          int count = 0;
          for (int i = 0; i < 120000; i++) {
              count++;
          }
          Log.e("CHAO", "method1: " + Thread.currentThread().getName());
  }

同不得静态方法再多线程中的调用和非静态的是一致的.

wait()首先wait()是属于Object类的方法,从源码给出的解释来看,wait()方法可以做到如下几点:(1)首先,调用了wait()之后会引起当前线程处于等待状状态。(2)其次,每个线程必须持有该对象的monitor(监视)。如果在当前线程中调 用wait()方法之后,该线程就会释放monitor的持有对象并让自己处于等 待状态。(3)如果想唤醒一个正在等待的线程,那么需要开启一个线程通过notify()或者notifyAll()方法去通知正在等待的线程获取monitor对象。如此,该线程即可打破等待的状态继续执行代码.

注意: wait()方法要使用在synchronized修饰的方法里面要不然会报异常,并且是synchronized()加锁的那个对象调用该方法.异常如下:

代码语言:javascript
复制
  java.lang.IllegalMonitorStateException: object not locked by thread before wait()

notify() , nitifyAll()notify()是属于Object类的方法.notify唤醒一个在这个对象上等待的线程监控。如果有任何线程在等待这个对象,其中一个线程被选择被唤醒。这个选择是任意的,并且发生在执行的自由裁量。一个线程在一个对象上等待通过调用wait()等方法来监视。nitifyAll唤醒所有的再等待中的线程.

注意:nitify唤醒的线程会在该线程的wiat之后继续执行,特别要注意的是调用wiat的同步语句块的对象锁要和nitify的同步语句块的对象锁是同一个,否则的话你是唤醒不了wait状态的.

代码语言:javascript
复制
final  Object obj = new Object();
     new Thread(){
          @Override
          public void run() {
              super.run();
              new Handler(getMainLooper()).post(new Runnable() {
                  @Override
                  public void run() {
                  //注意这个加锁对象
                      synchronized (obj) {
                          try {
                              Thread.sleep(1000);
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                          str = "WangChao";
                          Log.e("CHAO", "2" + str);
                          //注意唤醒方法的调用者
                          obj.notify();
                      }
                  }
              });
              Log.e("CHAO","run"+1);
              //注意这个加锁对象
              synchronized (obj) {
                  try {
                  //注意等待方法的调用者
                      obj.wait();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  if (str != null) {
                      Log.e("CHAO", "3" + str);
                  }
              }
          }
      }.start();

sleep()sleep()方法来自于Thread类,从源码给出的解释来看,sleep()方法可以做到如下几点:(1)首先,调用sleep()之后,会引起当前执行的线程进入暂时中断状态,也即睡眠状态。(2)其次,虽然当前线程进入了睡眠状态,但是依然持有monitor对象。(3)在中断完成之后,自动进入唤醒状态从而继续执行代码


总结

(1)在线程的运行过程中,调用该线程持有monitor对象的wait()方法时,该线程首先会进入等待状态,并将自己持有的monitor对象释放。(2)如果一个线程正处于等待状态时,那么唤醒它的办法就是开启一个新的线程,通过notify()或者notifyAll()的方式去唤醒。当然,需要注意的一点就是,必须是同一个monitor对象。(3)sleep()方法虽然会使线程中断,但是不会将自己的monitor对象释放,在中断结束后,依然能够保持代码继续执行。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-04-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 二 涉及的Java线程的知识点
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档