thread

来源:互联网 发布:3.0录音软件 编辑:程序博客网 时间:2024/06/03 17:49

java 按照顺序执行,不管开始到结束的路径有多少条。就像小王从A点到B点。如果我想让想小王去蛋糕店买一个蛋糕,那么小王会很顺利的完成,但是,我想让小王买蛋糕的时候,如果有卖西瓜的就买一个。小王就进了蛋糕店,这时候,一个卖西瓜的小贩刚好经过,小王就没有买的西瓜。说明如果完成一个任务的时候,需要多人协助完成,这就是线程的用处。

一、thread的生命周期

  1. 创建new
  2. 状态
    • runable
    • block
    • waiting/time waiting
  3. 终止interrupted

(一)创建

注意:以下源码来自于openjdk8,路径jdk8/jdk/src/java.base/share/java

class ThreadImplemented interfaces Runnable    private static native void registerNatives();    static {        registerNatives();    }//在clinit时候,运行代码块registerNatives,注册到native管理器中,如果不注册,需要在客户端使用System.loadLibrary('xxxx');

jdk源码:thread有10个构造函数,每个都调用了以下的init函数

 private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) {        //线程不能为空,为空抛出空指针异常        if (name == null) {            throw new NullPointerException("name cannot be null");        }           this.name = name;        Thread parent = currentThread();//获取实例化thread类的线程,可能是main线程,也可能是其他// 获取安全管理,从安全管理中得到安全的线程组 SecurityManager security = System.getSecurityManager();        if (g == null) {            if (security != null) {                g = security.getThreadGroup();            }               if (g == null) {                g = parent.getThreadGroup();            }           }           /* checkAccess regardless of whether or not threadgroup is           explicitly passed in. */        g.checkAccess();        /*         * Do we have the required permissions?         */        if (security != null) {            if (isCCLOverridden(getClass())) {                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);            }           }         /**         * Increments the count of unstarted threads in the thread group.在线程组中增加没有运行的线程的个数。     * Unstarted threads are not added to the thread group so that they     * can be collected if they are never started,      * 没有运行的线程是不能加入线程组的,以便它们被收集     * but they must be     * counted so that daemon thread groups with unstarted threads in them are not destroyed.     * 但是它们必须被计数以便线程组守护它们不被销毁         */          g.addUnstarted();        this.group = g;        this.daemon = parent.isDaemon();        this.priority = parent.getPriority();        if (security == null || isCCLOverridden(parent.getClass()))            this.contextClassLoader = parent.getContextClassLoader();        else            this.contextClassLoader = parent.contextClassLoader;        this.inheritedAccessControlContext =                acc != null ? acc : AccessController.getContext();        this.target = target;         setPriority(priority);        if (inheritThreadLocals && parent.inheritableThreadLocals != null)            this.inheritableThreadLocals =                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);        /* Stash the specified stack size in case the VM cares */        this.stackSize = stackSize;        /* Set thread ID */        tid = nextThreadID(); }

threadgroup

A thread group represents a set of threads. In addition, a thread group can also include other thread groups. The thread groups form a tree in which every thread group except the initial thread group has a parent.
(一个线程组代表线程的集合,另外,一个线程组能够有子组,就像集合有子集合一样,除了首线程组以外,其他线程组都有一个父节点,看来实现数据结构是一个树)
A thread is allowed to access information about its own thread group, but not to access information about its thread group’s parent thread group or any other thread groups
(一个线程被能够享用自己线程组的资源,但是不能先用父节点和其他节点的资源)

线程组主要是对多线程进行管理,

public class ThreadGroupextends Objectimplements Thread.UncaughtExceptionHandler
  1. 构造函数
ThreadGroup(String name)Constructs a new thread group.ThreadGroup(ThreadGroup parent, String name)Creates a new thread group

源码

public ThreadGroup(String name) {
this(Thread.currentThread().getThreadGroup(), name);
}

security

二、同步

原因:正常情况,执行程序,你不用担心其他问题,直接按照线程先后顺序执行就行了,因为你的CPU的核数要么只有一个,要么多个。只有一个只有一个一个排队执行,如果多个可以多个并行执行。 但是 事实恰恰不是这样的,因为如果只有一个核,排队执行,那么一台PC,只有在一段时间运行一个程序,其他都处于等待状态,这降低了效率,不能满足多服务需求。 为了解决这个问题不同的操作系统,使用并发的策略来解决,一般分为“抢占式”和“协调式”。抢占式是就是给每个程序一个时间分片,这段时间A跑,时间到了就让B跑。而这个时间分片是很短的(需调研)。这种策略在不同程序之间一般不会出现问题,但是在同一程序中,不同的线程就会出现问题,因为不同线程共享内存,会出现在怎样的问题呢?
一个线程的正在修改一个变量,改了一半,就是修改的内容还在寄存器里面,这是中止,另一个线程也来修改这个变量,修改成功了,按照逻辑A线程修改完了以后B线程才能修改,导致逻辑上不一致。
注意:同步是针对同一存储对象,比如实例、基本数据结构、集合、变量。所以全局属性为临界,局部属性不属于临界。
使用了锁的机制来,解决问题。一个是公开锁ReentrantLock类,一个是内部锁关键字synchronized。还有一个条件锁Condition类(只能进入代码段,不能运行线程)。

想锁对象怎么办,object的wait/notify

两个的缺点:不能中断试图得到锁的线程 锁不能超时 锁只有单一的条件。
使用java.util.concurrent

同步阻塞
syschronized(obj)//获取obj实例的锁。
volatile:编译器知晓该域并发,免锁机制
final变量:构造函数完成后才能发现变量
原子性:只有完成赋值
死锁:相互依赖。
threadlocal:线程变量不共享。
读写锁:ReentrantReadWritteLock, 多读取少修改共享变量。

阻塞队列

queue:先进先出

这里写图片描述
这里写图片描述

集合线程安全

原因:数据结构也属于多线程反问的共享变量,特别是散列表(比如hash表)。如果一个线程对散列表插入数据,申请空间,空间实际存的是指针。当存入指针前被阻塞,另外一个线程遍历散列表,就会出现错误。
解决方案:使用锁同步,而java类库已经为我们提供线程安全集合
java.util.concurrent._
concurrenthashmap
concurrentskiplistmap
concurrentskiplistset
concurrentskiplinkqueue

执行器

原因:当你需要创建多个生命周期短的线程时,那么就会带来更多的开销。
解决方案:使用线程池,线程池中的线程是的run为空,简称空线程,当你需要计算的时候,你只需要将runnable 对象交给线程池中的空线程,运行完后,线程不会停止,继续等待新的任务。
控制组
fork jion

同步器

为了协调多线程之间的协作,使用同步器可以简化同步的维护,
cyclicbarrier\exchanger\countdownlatch\semaphore\synchronousqueue

actor

  1. 使用消息异步,有效避免阻塞,产生锁。
  2. 线程之间使用消息通信,没有共享变量,有效的避免死锁。