zoukankan      html  css  js  c++  java
  • 并发编程(六):Java并发编程基础


    学习资料

    《Java并发编程的艺术》第4章 4.1~4.3


    1.线程简介

    1.1 什么是线程

    现代操作系统调度的最小单元,也叫轻量级进程

    一个进程可以创建多个线程,线程有各自的计数器,堆栈和局部变量等属性

    处理器在线程上高速切换(时间片调度),让使用者感觉到这些线程是同时执行的

    1.2 为什么要使用多线程

    使用多线程的原因:

    1. 更多的处理器核心:一个线程在同一时刻只能运行在一个CPU核上,有多个核的cpu就可以在同时刻运行多个线程,提高运行速度(并行)
    2. 更快的响应速度:将数据一致性不强的操作派发给其他线程处理(也可以是消息队列),能让请求更快处理完成,缩短响应时间
    3. 更好的编程模型:Java提供了良好且一致的多线程编程模型

    1.3 线程优先级

    thread.setPriority(n):设置线程优先级,1~10,默认为5

    有些操作系统会忽略优先级的设置,设置优先级没有效果(类Unix操作系统)

    在Wnidows下,优先级高的线程分配的时间片数量要多于优先级低的线程:

    • 频繁阻塞的线程(IO或休眠),应设置较高优先级
    • 偏重计算(CPU密集型)的线程应设置较低优先级,防止独占cpu

    1.4 线程运行状态

    线程六种状态:初始,运行,阻塞,等待,超时等待,终止

    线程状态切换:

    注意:

    • Java将操作系统线程状态的运行和就绪状态合并为运行态
    • synchronized对应的是阻塞状态,但是JUC的Lock接口对应的却是(超时)等待状态,因为JUC中该接口的实现都使用了LockSupport类的方法

    1.5 Daemon线程

    也叫守护线程,后台线程

    JVM中没有非Daemon线程时,所有的Daemon线程都要立即终止,可能会导致Daemon线程中的代码未执行完毕,Daemon线程中的finally块也不一定会执行

    thread.setDaemon(true);


    2.启动和终止线程

    2.1 构造线程

    构造线程是通过父线程来构造的,在Thread类的init方法中进行构造

    private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc) { 
    	//1.name参数有效性检查
    	//2.设置传入参数的值
    	//3.指定当前线程为父线程
    	//4.deamon,priority属性设置为父线程对应的属性
    	//5.将父线程的InheritableThreadLocal复制过来
    	//6.分配一个线程ID标记该线程
    }
    

    2.2 启动线程

    thread.start():当前线程(父线程)告知JVM,只要线程规划器空闲,立即启动thread线程

    最好为线程设置名称thread.setName(name),方便使用jstack排查问题

    2.3 理解中断

    中断可以理解为线程的一个标识位属性

    thread.interrupt():其他线程调用thread的该方法,将thread标记为中断

    thread.isInterrupted():true表示thread有中断标记,false表示没有中断标记,对终止状态的线程调用该方法返回结果都是false

    Thread.interrupted():清除该类对象的所有中断标记

    2.4 过期的suspend()、resume()和stop()

    thread.suspend()thread.resume()thread.stop()

    过期API不建议使用,不会释放(suspend)或者不会正确释放(stop)占有资源,导致程序出现不确定的状态

    suspend/resume暂停挂起可以使用等待通知机制来替代

    2.5 安全地终止线程

    通过对中断状态的交互控制来,还可以通过对Volatile类型的boolean变量来控制


    3.线程间通信

    3.1 volatile和synchronized关键字

    volatile修饰字段,表示任何对该变量的访问都要从共享内存中获取,且对它的改变也必须刷新回共享内存,保证所有线程对变量访问的可见性

    Synchronized可以修饰方法或者以同步块的形式来使用,确保多个线程在同一时刻只有一个线程处于方法或同步块中

    • 本质是对一个对象监视器(monitor)进行获取,排他,同一时刻只能有一个线程获取
    • 每个对象都有自己的监视器,只有获取到该监视器的线程才能进入到同步块,否则就会阻塞在同步队列SynchronizedQueue

    Synchronized示意图:

    3.2 等待/通知机制及范式

    等待方:消费者,WaitThread

    • 等待方原则:

      1. 要获取对象的锁
      2. 条件不满足,调用对象的wait()方法,被通知后仍要检查条件
      3. 条件满足则执行对应的逻辑
    • 示例代码:

      synchronized(obj){//锁对象
      	while(条件不满足){
      		obj.wait();
      	}
      	//对应处理逻辑
      }
      

    通知方:生产者,NotifyThread

    • 通知方原则:

      1. 要获取对象的锁
      2. 改变条件
      3. 通知所有等待在对象上的线程
    • 示例代码:

      synchronized(obj){
      	//修改条件
      	obj.notifyAll();
      }
      

    示意图:

    3.3 管道输入输出流

    管道输入/输出流用于线程之间的数据传输,传输媒介为内存,有四种具体实现:

    • 字节:
      • PipedOutputStream
      • PipedInputStream
    • 字符:
      • PipedWriter
      • PipedReader

    需要使用 connect() 将输入流和输出流绑定,否则会抛出IOException

    示例代码:

    ...main(...){
    	PipedWriter out=new PipedWriter();
    	PipedReader in=new PipedReader();
    	out.connect(in);    //绑定
    	Thread inThread=new Thread(new InThread(in));	//读取数据的线程
    	inThread.start();
        ...
    	out.write("A"); //main线程写
        ...
    }
    
    public class InThread implements Runnable{	
        private PipedReader in;
        public InThread(PipedReader in){
            this.in;
        }
        public void run(){
            ...
            in.read();	//读取
            ...
        }
    }
    

    3.4 thread.join()的使用

    thread.join():当前线程等待,thread线程执行终止后才继续执行当前线程

    逻辑结构与等待/通知类似

    超时重载类型:join(long millis)join(long millis,int nanos)

    3.5 ThreadLocal的使用

    ThreadLocal,线程变量,是一个以ThreadLocal对象为键,任意对象为值的存储结构

    一个线程可以通过ThreadLocal对象查询到绑定在这个线程上的一个值(线程独有的值)

    示例代码:

    ThreadLocal<LONG> tll=new ThreadLocal<>();
    tll.set();//设置值
    tll.get();//获取值
    

  • 相关阅读:
    ASP.NET Web API 中 特性路由(Attribute Routing) 的重名问题
    在 ASP.NET Web API 中,使用 命名空间(namespace) 来作为路由的参数
    【转】使用create_project.py创建cocos2d项目时出错
    WCF使用net.tcp绑定时的注意事项
    WCF:如何将net.tcp协议寄宿到IIS
    关于WCF服务的调试跟踪
    Windows Store Apps 开发转载
    如何让弹出窗口和页面产生联动?
    关于C# wpf DataGrid单元格双击设置单元格内容
    在WPF的DataGrid中对行添加单击事件
  • 原文地址:https://www.cnblogs.com/kenshine/p/14520444.html
Copyright © 2011-2022 走看看