美文网首页
线程间通信及android多线程解析

线程间通信及android多线程解析

作者: 程序猿峰岑 | 来源:发表于2019-12-06 20:54 被阅读0次

Synchroized的使用

使用synchroized关键字有两种方式
第一种:

  synchronized void methodA(){
        //......
    }

当线程访问方法A,由于是synchronized修饰,那么该线程就会去找monitor,monitor是该方法的对象。这样monitor就监视只有它能够访问methodA。
如果另外一个线程也来访问,该方法的monitor被占,这样他就会排在上一个线程的后面。上一个线程执行完,下一个线程接着执行。

synchronized void methodC(){
        //....
    }

如果现在有一个方法C它也是被synchronized修饰,那么如果有一个新的线程需要访问methodC,由于它们的monitor是一样的,所以该线程也是需要等上一个线程执行完后才能执行该线程。
第二种:

void methodB(){
        synchronized (MONITOR){
                //....
          }
    }

当有线程访问metohdB,由于外部没加锁,它会执行到方法内加锁的地方,如上代码所示,这里的monitor就是锁后面的括号的部分,如果这里的monitor跟methodA和methodC一样的。那么如果有新线程需要访问methodB,那么首先它需要看monitor是否被占领,如果被占了,那么该线程就会排在上一个线程的后面直到上一个线程执行完,该线程才能够访问方法B中的加锁内的代码块。

终止线程

终止线程现在有两种方法,第一种使用的是stop 另外一种使用的是interrupt
stop这种方法非常好用,它会在你需要停止该线程的时候执行。非常的高效暴力。但现在我们都知道,在大多数情况下我们会使用interrupt来中断线程

为什么要使用interrupt而不选择stop

首先stop太直接,直接kill该线程,这可能会导致结果的不可预测,很有可能导致你的程序出错。
那么我们使用interrupt,看下它是如何打断线程的,代码如下:

public class ThreadInteractionDemo implements TestDemo {
    @Override
    public void runTest() {
        Thread thread = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 1_000_000; i++) {
                    System.out.println("number:" + i);
                }
            }
        };
        thread.start();
        thread.interrupt();
    }
}

执行结果:


image.png

stop和interrupt

我们会发现子线程并未被打断。这又是为什么呢?其实interrupt只是把线程标记为中断状态。它通知该线程被终止但它并不执行中断线程的操作。真正执行被打断的是isInterrupted()。

for (int i = 0; i < 1_000_000; i++) {
                    if (isInterrupted())
                    System.out.println("number:" + i);
                }

还有一种静态的方法Thread.interrupted(),这种方法跟上面的isInterrupted()最大的区别是该方法在执行的时候把中断线程的状态设置为false,这样该线程就在被中断状态标记的时候跳过,过后线程又开始运行。也就是它不会中止线程。而Thread.interrupted()可能会使你的线程中止。

wait和notify

在讲解 wait之前我们先看这个例子,thread1睡眠500ms执行printlnString()方法,thread2睡眠1000ms执行initString()方法。printlnString()中如果shareString==null,这里的循环一直执行,直到1s后shareString被赋值,由于synchronized锁,导致程序一直在while代码块执行

private String shareString;
    private synchronized void initString(){
        shareString = "hello android thread";
    }

    private synchronized void printlnString(){
        while (shareString == null){
            
        }
        System.out.println("String:"+shareString);
    }
    @Override
    public void runTest() {
        final  Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                printlnString();
            }
        });
        thread1.start();

        final Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();

                }
                initString();
            }
        });
        thread2.start();

    }

为了让锁暂时释放掉,我们可以考虑使用wait.让线程在monitor中的wait队列中等待,直到1s后初始化shareString,我们再使用notify唤醒线程执行printlnString方法并完成打印。注意:如果等待的线程比较多的情况下,我们可以使用notifyAll,wait和notify是object并不是线程的。
使用场景:wait和notify的一般情况是由于有些资源不能第一时间得到,需要过一段时间才能够拿到,这个时候就可以考虑使用wait和notify

 private synchronized void initString(){
        shareString = "hello android thread";
        notify();
    }

    private synchronized void printlnString(){
        while (shareString == null){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("String:"+shareString);
    }

join

这个方法作用是把join线程插入到正在执行线程的前面,例如:

final Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                
            }
        });
        thread1.start();
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    thread1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread2.start();

现在正在执行thread2线程,突然在thread2 中调用了thread1.join(),那么它就会先执行thread1,等执行完后再执行thread2。

yield

它是一个静态方法,调用这个线程的时间链暂时分配给跟它一样优先级的线程。

handler机制

handler机制的本质就是在指定运行中的线程中执行代码,如果你看了它源码就会发现无论是设置数据还是取数据都是不断的循环。那为什么它没有阻塞线程呢?原因是Thread默认是没有Looper,如果要使用handler就必须为线程创建Looper,我们认为的阻塞线程其实指的是UI线程,也就是ActivityThread,而ActivityThread在创建时就会初始化Looper。这个也就是我们在Activity可以直接使用Handler的原因。
handler机制工作原理:
1.创建与线程绑定的Looper,同时会创建一个与之关联的MessageQueue用于存放消息
2.开启消息循环,从MessageQueue中获取待处理消息,若无消息会进入等待状态
3.通过Handler发送消息,此时会将Message入队列到MessageQueue中,并且唤醒等待的Looper
4.Looper获取的消息会投递给对应的Handler处理

ThreadLocal

ThreadLocal指的线程之间不共享的变量,他不是一个线程。例如:我们在thread1中threadLocal设置值为1。thread2中threadlocal设置为2。那么在thread1中取值的时候为1,threadLocal2中取值为2,代码如下:

   private Thread thread1(){
        return new Thread(new Runnable() {
            @Override
            public void run() {
                //线程1
                threadLocal.set(1);
                threadLocal.get();1
            }
        });
    }

    private Thread thread2(){
        return new Thread(new Runnable() {
            @Override
            public void run() {
                //线程2
                threadLocal.set(2);
                threadLocal.get();2
            }
        });
    }

知识点除了syncTask和Executor线程池外差不多知识点都讲解完了,如果线程还没有讲到的知识点,或者对上面不是很了解存在疑惑的,都可以在留言区留言,同时你也可以分享你对线程的理解在留言区,共同学习,一起成长。秉着学习和交流的心态让我们走的更远。

相关文章

网友评论

      本文标题:线程间通信及android多线程解析

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