线程

作者: jacky123 | 来源:发表于2016-06-29 21:56 被阅读445次

线程的状态

  • 新状态:线程对象已经创建,还没有在其上调用start()方法。

  • 就绪:当线程有资格运行,但调度程序还没有把它选定为运行线程,这时候线程所处的状态就做就绪状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到可运行状态。另外yield可以让线程由“运行状态”进入到“就绪状态”。

  • 运行:线程调度程序从可运行池中选择一个线程来执行。这也是线程进入运行状态的唯一一种方式。

  • 等待/阻塞/睡眠:这是线程有资格运行时它所处的状态。实际上这个三状态组合为一种,其共同点是:线程仍旧是活的,但是当前没有条件运行。换句话说,它是可运行的,但是如果某件事件出现,他可能返回到可运行状态。另外wait可以让线程由“运行状态”进入到“等待(阻塞)状态”。

  • 死亡态:当线程的run()方法完成时就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦死亡,就不能复生。 如果在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。


线程方法

1. notify/notifyAll

  • notifyAll注释为

Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling one of the {@code wait} methods.
This method should only be called by a thread that is the owner
of this object's monitor.

一旦一个对象调用了wait方法,必须要采用notify()和notifyAll()方法唤醒该进程;


关于线程的常见问题

1. Object的wait和notify/notifyAll如何实现线程同步?

在Object.java中,定义了wait(), notify()和notifyAll()等接口。
wait()的作用是让当前线程进入等待状态,同时,当object调用wait()方法会让当前线程释放它所持有object对象锁。
而notify()和notifyAll()的作用,则是唤醒在此对象监视器上等待的单个/全部线程。

a.关于wait的一个错误案例:

final Object object = 1;

new Thread(){
    @Override
    public void run() {
        synchronized (object){
            Log.e("jack",Thread.currentThread().getName()+"->"+1);
            try {
                /**
                 * object not locked by thread before wait(),
                 * 这是因为我们锁住的是object对象,但是wait,相当于this.wait,解锁的是当前对象。
                 * 当前对象并没有locked,所以会有这个错误。
                 */
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.e("jack",Thread.currentThread().getName()+"->"+2);
        }
    }
}.start();

b.关于notify的一个案例,注意同步对象:

//是否满足某种条件的标识
boolean flag = false;

public void onWait(View view) {
    //每次点击初始化 falg 的值
    flag = false;
    final Thread t1 = new Thread("Thread 1") {
        @Override
        public void run() {
            /**
             * 这边锁住的是 MainActivity 的对象。
             * 在run方法里通过 wait 释放 MainActivity对象锁,如果想要再次唤起这个线程,肯定还是
             * MainActivity.this.notify();
             *
             * 如果这边同步this,则代表当前线程对象。
             */
            synchronized (MainActivity.this) {
                //不满足条件就在这里等待
                while (!flag) {
                    Log.e("jack", Thread.currentThread().getName() + "->" + 1);
                    try {
                        MainActivity.this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.e("jack", Thread.currentThread().getName() + "->" + 2);
                }
            }
        }
    };
    t1.start();

    Thread t2 = new Thread("Thread 2") {
        @Override
        public void run() {
            try {
                //保证"Thread 1"先执行
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (MainActivity.this) {
                try {
                    Log.d("jack", Thread.currentThread().getName() + "->" + 3);
                    Thread.sleep(1000);
                    flag = true;   //满足了某种条件
                    /**
                     * 唤醒在 MainActivity.this 对象监视器上等待的单个/全部线程。
                     */
                    MainActivity.this.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.d("jack", Thread.currentThread().getName() + "->" + 4);
            }
        }
    };
    t2.start();
}
Paste_Image.png

线程1执行打印了 "Thread 1->1",然后通过 MainActivity.this.wait();释放了当前线程所持对象的锁...

2. wait和yield(或sleep)的区别?

wait()是让线程由“运行状态”进入到“等待(阻塞)状态”
yield()是让线程由“运行状态”进入到“就绪状态”,从而让其它具有相同优先级的等待线程有机会获取执行权;但是,并不能保证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权。
wait()是会在线程释放它所持有对象的同步锁,而yield()方法不会释放锁。
Thread.sleep(long millis)和Thread.sleep(long millis, int nanos)静态方法强制当前正在执行的线程休眠.当线程睡眠时,它入睡在某个地方,在苏醒之前不会返回到可运行状态。当睡眠时间到期,则返回到可运行状态。


线程同步

1. wait notify 来实现

以android中的HandlerThread的源码为例说明

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        /**
         * 获取到当前Thread的Looper对象
         * 然后通知 getLooper 方法,这个时候可以返回(同步)
         */
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

public Looper getLooper() {
    if (!isAlive()) {
        return null;
    }
    
    // If the thread has been started, wait until the looper has been created.
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                /**
                 * 等待run方法的Looper对象初始化完成
                 */
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}
2. synchronized

a. 说一下 synchronized与static synchronized 的区别

synchronized是对类的当前对象进行加锁,防止其他线程同时访问该对象的所有synchronized块,其实synchronized就相当于this.synchronized
static synchronized恰好就是要控制类的所有对象的访问了,static synchronized的作用是同步线程访问该类的所有对象代码块。

3. CountDownLatch

一个同步辅助类(大名鼎鼎的java.util.concurrent包),在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

4. 重入锁ReentrantLock
  • 重入性:指的是同一个线程多次试图获取它所占有的锁,请求会成功。当释放锁的时候,直到重入次数清零,锁才释放完毕。
  • ReentrantLock将由最近成功获得锁,并且还没有释放该锁的线程所拥有。如果当前线程已经拥有该锁,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。
  • 此类的构造方法接受一个可选的公平参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。
  • 常用方法

lock
unlock
isHeldByCurrentThread
getHoldCount

相关文章

  • Android

    线程间通信 主线程和工作线程主线程和工作线程 工作线程与工作线程工作线程与工作线程 为什么主线程Looper.lo...

  • 三、操作系统之线程

    前言 什么是线程 引入线程的原因 线程的概念 线程和进程的关系 线程结构 线程有点 多线程模型 用户线程和内核线程...

  • Thread

    队列 线程锁 多线程,线程池 队列 多线程爬虫示例 多线程 自定义线程 线程池

  • 总结多线程与设计模式+synchronized+性能+高吞吐+死

    Java线程 Java语言的线程 何谓线程 线程启动 线程的暂时停止 线程的共享互斥 线程的协调 线程的状态转移 ...

  • 多线程编程

    摘要 线程概念,线程与进程的区别与联系学会线程控制,线程创建,线程终止,线程等待了解线程分离与线程安全学会线程同步...

  • java线程池

    线程VS线程池 普通线程使用 创建线程池 执行任务 执行完毕,释放线程对象 线程池 创建线程池 拿线程池线程去执行...

  • java并发之守护线程

    java中有两种线程,用户线程和守护线程用户线程:主线程停止时,用户线程不会停止守护线程:主线程停止时,守护线程也...

  • Java线程池的使用

    线程类型: 固定线程 cached线程 定时线程 固定线程池使用 cache线程池使用 定时调度线程池使用

  • 线程基础知识

    线程学习 线程的基础知识 线程是什么? 线程和进程的关系 线程的6个状态 线程优先级 主线程、多线程、后台线程的概...

  • 多线程介绍

    一、进程与线程 进程介绍 线程介绍 线程的串行 二、多线程 多线程介绍 多线程原理 多线程的优缺点 多线程优点: ...

网友评论

    本文标题:线程

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