线程

线程的状态

  • 新状态:线程对象已经创建,还没有在其上调用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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 该文章转自:http://blog.csdn.net/evankaka/article/details/44153...
    加来依蓝阅读 12,077评论 3 87
  • Java多线程学习 [-] 一扩展javalangThread类 二实现javalangRunnable接口 三T...
    影驰阅读 8,094评论 1 18
  • 本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。 首先讲...
    李欣阳阅读 7,200评论 1 15
  • 写在前面的话: 这篇博客是我从这里“转载”的,为什么转载两个字加“”呢?因为这绝不是简单的复制粘贴,我花了五六个小...
    SmartSean阅读 10,238评论 12 45
  • 1.解决信号量丢失和假唤醒 public class MyWaitNotify3{ MonitorObject m...
    Q罗阅读 4,446评论 0 1

友情链接更多精彩内容