美文网首页
多线程基础

多线程基础

作者: 木山手札 | 来源:发表于2019-10-27 13:50 被阅读0次

    JVM中的线程

    • 多线程共享进程中的堆和方法区资源
    • 每个线程有自己的程序计数器和栈
      • 程序计数器记录当前线程要执行的地址,为了cpu下次获取时间片执行线程时知道从哪里执行

    JVM线程模型

    线程的创建方式

    • 继承Thread类
    • 实现Runable接口
    • 实现Callable<?>

    这三种创建线程的差异在哪里

    wait()

    • 一个线程调用共享变量的wait()时,该调用线程会给阻塞,并且释放锁,直到其它线程调用共享变量的notify()、notifyAll()唤醒返回,或其线程调用该线程的interrupt()方法,抛异常返回
    • 防止虚假唤醒,不停的去测试该线程被唤醒的条件是否满足,不满足继续等待
    synchronized(obj){
      while(条件不满足){
        obj.wait();
      }
    }
    
    • 同步机制生产者消费例子
    public class ProductConsumer {
        private static final Integer capacity = 5;
    
        private static final LinkedBlockingQueue queue = new LinkedBlockingQueue(capacity);
    
    
        public static void main(String[] args) throws InterruptedException, IOException {
            Producer producer = new Producer();
            Consumer consumer = new Consumer();
    
            Thread p1 = new Thread(producer);
            Thread c1 = new Thread(consumer);
            Thread c2 = new Thread(consumer);
    
            p1.start();
            c1.start();
            c2.start();
    
            p1.join();
            c1.join();
            c2.join();
    
            System.out.println("will read in wait");
            System.in.read();
        }
    
        private static class Producer implements Runnable {
    
    
            @Override
            public void run() {
                try {
                    while (true) {
                        synchronized (queue) {
                            while (queue.size() == capacity) {
                                System.out.println("producer wait");
                                queue.wait();
                            }
                            long product = System.currentTimeMillis();
                            queue.add(product);
                            System.out.println("product=" + product);
                            queue.notifyAll();
                        }
                        TimeUnit.MILLISECONDS.sleep(100);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        private static class Consumer implements Runnable {
    
            @Override
            public void run() {
                try {
                    while (true) {
                        synchronized (queue) {
                            while (queue.size() == 0) {
                                System.out.println("consumer wait");
                                queue.wait();
                            }
                            System.out.println("consumer=" + queue.take());
                            queue.notifyAll();
                        }
                        TimeUnit.SECONDS.sleep(2);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    notify()/notifyAll()

    • 需要获取锁才能调用
    • 一个线程调用共享对象的notify()会唤醒一个在共享变量上调用wait()后被挂起的线程,唤醒线程是随机的
    • 被notify()唤醒后的线程不能马上执行,需要先获取锁
    • notifyAll()唤醒在共享变量上所有被挂起的线程,只有竞争到锁的线程才能执行
    • notifyAll()只会唤醒调用该方法前调用wait()而被放入共享变量等待集合的线程

    join()

    • 调用join()线程等待join线程执行完毕后在进行后续处理
    • 调用join()的线程被interrupt后会抛InterrupedException

    yield()

    • 暗示线程调度器当前线程可以让出cpu的使用权,线程调度器可以忽略这个暗示
    • 让出cpu使用权后线程并不会阻塞挂起,而是处于就绪状态

    线程中断

    • interrupt():设置线程的中断标志,仅仅是设置标志,线程会继续执行,如果线程之前调用了wait、join、sleep会抛出InterruptedException
    • isInterrupted():检测当前线程是否被中断,不清除中断标志
    • interrupted():检测线程是否被中断,如果当前线程被中断,则会清除中断标志,
     public static boolean interrupted() {
            // 获取当前线程,而不是调用interrupted()的实例对象线程中的中断标志
            return currentThread().isInterrupted(true);
        }
    
    • 判断中断标志如何输出
         Thread t1 = new Thread(()->{
                for(;;);
            });
    
            t1.start();
            t1.interrupt();
    
            Thread.currentThread().interrupt();
            
            System.out.println(t1.isInterrupted());
            System.out.println(t1.interrupted());
            System.out.println(Thread.interrupted());
            System.out.println(t1.isInterrupted());
    
            t1.join();
    

    死锁

    • 死锁产生的四个条件:互斥、请求并持有、不可剥夺、环路
    • 死锁的原因和申请资源的顺序有关,资源申请有序性可以避免死锁

    如何实现一个死锁程序

    ThreadLocal

    内部结构ThreadLoacl、TheradLoalMap
    Thread中的两个变量threadLoacls、inheritableThreadLocals
    ThreadLoacl中的set、get、rmove方法实现
    子线程、父线程共享数据

    相关文章

      网友评论

          本文标题:多线程基础

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