浅谈一下Android中的多线程


1、什么是线程

线程是程序执行的最小单位,是进程的一个执行流。

2、什么是进程

系统资源分配的基本单位,是程序执行时的一个实例,在程序运行时创建。

3、进程和线程的联系

一个进程至少有一个线程,每个进程都有独立的地址空间,每启动一个进程系统就会为它分配地址空间,而同一个进程里面的线程共享进程中的所有资源,每个线程都有自己的堆栈和局部变量。

4、Android中实现多线程的方式:

4.1 继承Thread类
 class ThreadTest extends Thread{
        @Override
        public void run() {
            super.run();
            //耗时任务
        }
    }

启动方式

new ThreadTest().start();

这种方式在Android中不推荐使用,如果使用new Thread()创建一个线程,有可能会导致内存泄漏。由于java的特性内部类会持有外部类的引用,如果内部类是一个Thread,该内部类会持有外部类(Activity等)的引用,导致外部类在应该释放的时间不能被释放,从而导致内存泄漏。

4.2 实现Runnable接口
 private class RunnableTest implements Runnable {
        @Override
        public void run() {
            //doSomthing()
            //耗时操作
        }
    }

启动方式

RunnableTest runnable = new RunnableTest();
Thread runnable1 = new Thread(runnable, "线程一");
Thread runnable2 = new Thread(runnable, "线程二");
Thread runnable3 = new Thread(runnable, "线程三");

runnable1.start();
runnable2.start();
runnable3.start();
4.3 Handler
public class HandlerActivity extends AppCompatActivity {

    private Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler_activity);

        //创建 Handler
        final MyHandler handler = new MyHandler(this);

        btn = findViewById(R.id.btn_handler);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(()->{
                    //使用 handler 发送空消息
                    handler.sendEmptyMessage(0);
                }).start();
            }
        });
    }
    //静态内部类不会持有外部类的引用
    private static class MyHandler extends Handler {

        //弱引用持有HandlerActivity , GC 回收时会被回收掉
        private WeakReference<HandlerActivity> weakReference;

        public MyHandler(HandlerActivity activity) {
            this.weakReference = new WeakReference(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            HandlerActivity activity = weakReference.get();
            super.handleMessage(msg);
            if (null != activity) {
                //执行业务逻辑
            }
        }
    }
    
    @Override
    protected void onDestroy() {
        //移除所有回调及消息
        myHandler.removeCallbacksAndMessages(null);
        super.onDestroy();
    }
}
4.4 AsyncTask
    private class LoginTask extends AsyncTask<String, Void, List<String>> {
        @Override
        protected List<String> doInBackground(String... strings) {
            //子线程执行
            return "";
        }

        @Override
        protected void onPostExecute(List<String> list) {
           //ui线程执行
           //当doInbackground() return后执行
        }
    }

创建方式

LoginTask loginTask = new LoginTask();
loginTask.execute();

同一个Task只能调用一次execute()方法。

4.5 HandlerThread
   //创建HandlerThread实例对象
   HandlerThread ht = new HandlerThread("ht");

   //启动线程
   ht.start();

  //创建工作线程Handler和重写handleMessage()
  Handler handler = new Handler(ht.getLooper() ) {
            @Override
            public boolean handleMessage(Message msg) {
                //消息处理
                //执行在UI线程
                return true;
            }
        });


  //子线程中的操作
  //使用工作线程Handler向UI线程的消息队列发送消息
  Message msg = Message.obtain();
  msg.what = 0; //消息的标识
  msg.obj = "handlerThread test"; // 消息的存放
  handler.sendMessage(msg);

  //结束线程
  ht.quit();
4.6 IntentService
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startIntentService();
    }

    public void startIntentService() {
       // 创建需要启动的IntentService的Intent
        Intent intent = new Intent(this, MyIntentService.class);
        startService(intent);
    }
}


public class MyIntentService extends IntentService {
    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        //IntentService会使用单独的线程来执行该方法的代码
        //执行耗时任务
    }
}
4.7 线程池

5、线程的常用方法和几种状态

run()//包含线程运行时所执行的代码。

start()//用于启动线程,调用start()后并不会立马执行,而是处于就绪状态,需要等cpu调度才开始执行。

sleep()/sleep(long millis)//线程休眠,交出CPU,让CPU去执行其他的任务,然后线程进入阻塞状态,sleep方法不会释放锁。

yield()//使当前线程交出CPU,让CPU去执行其他的任务,但不会是线程进入阻塞状态,而是重置为就绪状态,yield方法不会释放锁。

join()/join(long millis)/join(long millis,int nanoseconds)//等待线程终止,直白的说 就是发起该子线程的线程 只有等待该子线程运行结束才能继续往下运行。

wait()//交出cpu,让CPU去执行其他的任务,让线程进入阻塞状态,同时也会释放锁。

interrupt()//中断线程,通过interrupt方法和isInterrupted()方法来停止正在运行的线程,注意只能中断已经处于阻塞的线程。

6、如何安全结束线程

  1. stop():强行终止线程,可能发生无法预料的结果。已经过时,不推荐使用。
  2. interrupt():中断线程。当线程处于阻塞状态时,如使用sleep(),同步锁wait(等方法时会使线程进入到阻塞状态,当程序调用interrupt()方法时,会抛出InterruptedException异常,通过捕获该异常然后跳出循环,从而结束该线程。当线程未处于阻塞状态时,实际上是通过判断线程的中断标记来结束循环:当使用interrupt()方法时,中断标志就会置为true。
  3. 使用退出标志:最直接的方式设一个Boolean的参数,通过控制这个参数true或者false来控制循环是否结束。

7、java线程调度原理:

java多线程内存模型是基于cpu缓存模型建立的,它可以屏蔽掉不同硬件和操作系统的内存访问差异,实现不同平台具有一致的并发效果。

  1. java内存模型(Java Memory Model JMM):java线程之间的通信由java内存模型(JMM)控制,JMM决定了一个线程对共享变量的写入何时对另一个线程可见。线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地化内存,本地内存中存储了该线程用来读写共享变量的副本。
    在这里插入图片描述
  2. 高速缓存
    为了弥补处理器与内存之间读写速率的差距,在主内存和处理器之间加了高速缓存。处理器执行读写操作时直接与高速缓存交互,不直接与主内存进行通信。高速缓存主要存储的是准备存入主内存中的数据,也可以是用来执行线程操作的主内存中的数据副本。
  3. Java线程调度机制
    java线程的调度主要由jvm来负责,按照特定的机制为多个线程分配cpu的使用权。
    线程调度模型分为两类:分时调度模型和抢占式调度模型
    分时调度模型:轮流获取cpu时间片,每个线程占有的CPU时间长度一致。
    抢占式线程调度:按照线程优先级来决定先执行哪个线程,如果优先级一致则随机挑选一个,不能保证每个线程平均占有CPU时间长度。jvm采用的是抢占式线程调度。

8、线程安全问题

线程安全其实就是保证多线程环境下多个线程同时对某一对象或资源进行操作不会出错。而实现线程安全要保证三个点:原子性、可见性、有序性。

  • 原子性:表示不可分割的、不可被中断的,中断只能在该操作之前或者结束之后,在多线程环境下保证单个线程操作符合预期逻辑。
  • 可见性:指一个线程对某一个变量的修改能够被其他线程及时看到。
  • 有序性:指一个处理器在为一个线程执行的内存访问操作,对于另一个处理器上运行的线程来看是乱序的。处理器为了提高指令的执行效率,往往不是按程序顺序注意执行指令的,而是哪条指令就绪就先执行哪条指令,这就是处理器的乱序执行。

9、实现线程安全

实现线程安全要保证原子性、可见性和有序性,常见的实现线程安全方法:互斥同步和非阻塞同步。

10、互斥同步

synchronized:synchronized机制是给共享资源上锁,只有拿到锁的线程才可以访问共享资源,能保证在同一时刻最多只有一个线程执行同一个对象的同步代码,具有原子性和可见性。实现机制依赖于软件层面上的jvm,属于悲观锁。
ReentrantLock:表示可以被线程多次重复进入进行读取操作。除了能完成synchronized的操作外,还提供了响应中断锁、可轮询锁请求、定时锁等避免多线程死锁的方法。实现机制依赖于特殊的cpu指定,不受jvm限制。使用ReentrantLock上锁之后需要手动解锁。默认是非公平,可以设置为公平锁,但会导致性能急剧下降。

11、非阻塞同步(无锁)

在并发环境下,某个线程对共享变量先进行操作,如果没有其他线程争用共享数据那操作就成功;如果存在数据的争用冲突,那就才去补偿措施,比如不断的重试机制,直到成功为止,因为这种乐观的并发策略不需要把线程挂起,也就把这种同步操作称为非阻塞同步(操作和冲突检测具备原子性)。在硬件指令集的发展驱动下,使得 “操作和冲突检测” 这种看起来需要多次操作的行为只需要一条处理器指令便可以完成,这些指令中就包括非常著名的CAS指令(Compare-And-Swap比较并交换)。

public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        //cas操作
        do {
            //volatile保证读线程取到的值和主内存存放的一致
            var5 = this.getIntVolatile(var1, var2);
             //compareAndSwapInt是一个原子操作,只有当var1+var2内存地址处的变量与var5的值
            //相同时,给这个变量赋值var5+var4,返回true
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

保证线程的安全需要可见性、有序性、原子性,这段代码中通过volatile保证了可见性和有序性,通过CAS保证了原子性。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值