线程与进程

基本概念

并发:宏观并行,微观交替执行
并行:在同一时刻处理进程
同步:进程间相互依赖,下个进程会等待上个进程的结果
互斥:进程间相互排斥的使用临界资源的现象
异步:进程彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这一事件完成后再工作。
多线程:多线程是程序设计的逻辑层概念,是进程中并发运行的一段代码。是实现异步的手段。

程序:一段静态的代码,一组指令的有序集合,它本身没有任何运行的含义。
进程:进程是系统进行资源分配(最小单位)和调度的一个独立单位。是程序的一次动态执行。
线程:线程是进程中执行运算的最小单位,执行处理机调度的基本单位。引入原因:减少程序并发执行时所付出的时空开销

死锁
多个进程竞争资源导致无限期阻塞、相互等待的一种状态

  1. 互斥(资源只允许一个进程持有)
  2. 占有并等待(进程已有资源,继续请求其他临界资源)
  3. 不可抢占(进程资源不会被其他进程抢占)
  4. 循环等待(多个线程形成环形等待关系)

饥饿
进程长时间等待不被执行
活锁
进程占有资源后都主动释放资源给其他进程使用

多线程优点:多线程容易调度,有效地实现并发性。对内存的开销比较小。创建线程比创建进程要快。

全局安全点

线程状态
在这里插入图片描述

Runnable接口

通过实现Runnable接口来创建线程

public interface Runnable {
    public abstract void run();
}

Callable和Future创建线程
线程池创建线程

Thread类

通过继承Thread类来创建线程

public class Thread implements Runnable {
	//默认构造方法,线程名为Thread-0
	public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    public Thread(String name) {
        init(null, null, name, 0);
    }
    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }
	//线程组,Runnable接口,线程名,栈大小
	private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }
    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();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
			//通过安全管理器获得线程组
            if (security != null) {
                g = security.getThreadGroup();
            }
			//如果安全管理器未提供线程组则使用parent的线程组
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }
        g.checkAccess();
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        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);
        //继承父线程的ThreadLocal
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        this.stackSize = stackSize;
        tid = nextThreadID();
    }
}

成员变量

//当前线程名
private volatile String name;
//优先级
private int            priority;
private Thread         threadQ;
//指向操作系统支持的线程
private long           eetop;
//是否为守护线程
private boolean     daemon = false;

private Runnable target;
//当前线程所在线程组
private ThreadGroup group;
//线程栈大小
private long stackSize;
//线程序号
private static long threadSeqNumber;
//记录线程状态二进制表示:new=0,runnable=100,terminate=10
//block=10000000000,wait=10000,time_wait=100000
private volatile int threadStatus = 0;

主要方法
start()
线程由new状态转为runnable状态

public synchronized void start() {
	//如果线程状态不为new
	if (threadStatus != 0)
    	throw new IllegalThreadStateException();
    //将当前线程加入线程组
    group.add(this);
    //启动标识
    boolean started = false;
    try {
        start0();
        started = true;
    } finally {
        try {
        	//如果启动失败则从线程组中移除
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
        }
    }
}
private native void start0();

wait()
释放锁,进入ObjectMonitor对象监视器中的_waitSet队列,挂起线程,等待唤醒,使用wait和notify时需要持有对象锁

//wait()->wait(0)
//jdk1.8:wait(long,int)->nanos>0,timeout++
public final native void wait(long timeout) throws InterruptedException;

notify()
唤醒_waitSet队列的一个线程,同步块执行完成后才释放锁
notifyAll()
唤醒_waitSet队列中的所有线程进入_EntryList竞争资源,同步块执行完成才释放锁
sleep(long time)
线程不释放锁进入阻塞状态,到指定时间后进入runnable状态,等待cpu调度执行
isAlive()
判断当前线程是否存活

public final native boolean isAlive();

join()
使当前线程阻塞,直到调用join的线程执行完成,通过调用当前线程的wait方法实现

//实际相当于调用wait(0)
public final void join() throws InterruptedException {
        join(0);
}
//底层调用wait方法
public final synchronized void join(long millis)
    throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;
    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (millis == 0) {
    	//如果当前线程存活
        while (isAlive()) {
        	//执行线程等待,当当前线程执行完成会自动调用其notifyAll方法
            wait(0);
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}
//类似wait(long,int)方法将计算的millis结果传给方法join(long millis)
public final synchronized void join(long millis, int nanos){}

interrupt()
中断线程,设置中断标志位,阻塞时调用抛出异常

//isInterrupted 根据中断标志位判断线程是否中断
//interrupted 根据中断标志位判断线程是否中断,并清除中断状态

yield()
使当前线程让出cpu资源,进入runnable状态,等待调度

public static native void yield();

currentThread()
返回当前正在执行的线程对象的引用

public static native void currentThread();

ThreadGroup
线程组表示一个线程的集合。此外,线程组也可以包含其他线程组。允许线程访问关于其线程组的信息,但不允许访问关于其线程组的父线程组或任何其他线程组的信息。

public class ThreadGroup implements Thread.UncaughtExceptionHandler {
	//持有的父线程组
	private final ThreadGroup parent;
	//当前线程组中线程数量
	int nthreads;
	//存放线程的数组
    Thread threads[];
}

线程通信
PipedOutputStream
PipedInputStream
PipedReader
PipedWriter

Lock

Lock实现提供比使用synchronized方法和语句可以获得的更广泛的锁定操作。

public interface Lock {
	//获得锁。
	void lock();
	//获取锁定,竞争锁的过程可以响应中断,退出等待
	void lockInterruptibly() throws InterruptedException;
	//返回一个新Condition绑定到该Lock实例
	Condition newCondition();
	//可轮询锁,如果可用,则获取锁定,并立即返回值为true 。 如果锁不可用,则此方法将立即返回值为false 
	boolean tryLock();
	//定时锁,如果在给定的等待时间内是空闲的,并且当前的线程尚未 interrupted,则获取该锁。
	boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
	//释放锁。
	void unlock();
}
Condition

Condition取代了对象监视器方法的使用。一个Condition实例本质上绑定到一个锁,可实现多路通知。

public interface Condition {
	//导致当前线程等待直到发信号或interrupted
	void await() throws InterruptedException;
	//使当前线程等待直到发出信号或中断,或指定的等待时间过去
	boolean await(long time, TimeUnit unit) throws InterruptedException;
	//使当前线程等待直到发出信号或中断,或指定的等待时间过去。 
	long awaitNanos(long nanosTimeout) throws InterruptedException;
	//使当前线程等待直到发出信号,不响应中断
	void awaitUninterruptibly();
	//使当前线程等待直到发出信号或中断,或者指定的最后期限过去 
	boolean awaitUntil(Date deadline) throws InterruptedException;
	//唤醒一个等待线程
	void signal();
	//唤醒所有等待线程
	void signalAll();
}
ReentrantLock—可重入锁

synchronized功能扩展,jdk1.6后与synchronized性能差距不大

public class ReentrantLock implements Lock, java.io.Serializable {
	private final Sync sync;
	//构造方法,默认不公平
	public ReentrantLock() {
        sync = new NonfairSync();
    }
    //设置公平或非公平锁
    //公平锁:先提出锁获取请求优先分配
	//非公平锁:按随机、就近原则分配,默认为非公平锁,非公平锁执行效率更高。
	public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

	//获取竞争队列中的线程数
	public final int getQueueLength() {
        int n = 0;
        for (Node p = tail; p != null; p = p.prev) {
            if (p.thread != null)
                ++n;
        }
        return n;
    }
    //获得条件队列中的线程数
    protected final int getWaitQueueLength() {
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
        int n = 0;
        for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
            if (w.waitStatus == Node.CONDITION)
                ++n;
        }
        return n;
    }
}
Semaphore

一个计数信号量,是多锁的扩展,本质上是使用AbstractedQueuedSynchronizer实现的一个共享锁。

public class Semaphore implements java.io.Serializable {
	//持有的同步器
	private final Sync sync;
	//构造器中初始化同步器为公平还是非公平
	public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

	//获得指定数量信号量,如果不足则阻塞线程
	public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }
    //释放指定数量信号量
    public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits);
    }
}
ReadWriteLock接口

维护一对关联的锁 ,一个用于读操作,一个用于写操作

public interface ReadWriteLock {
    //返回用于读取的锁
    Lock readLock();
    //返回用于写入的锁
    Lock writeLock();
}
ReentrantReadWriteLock

可重入读写锁,共享锁(线程对读取操作共享),排他锁(线程对写入操作互斥)
注意事项

  • 读锁获得Condition会抛出异常
  • 只有读锁与读锁之间不阻塞
成员变量
/** 内部类提供的读取锁 */
private final ReentrantReadWriteLock.ReadLock readerLock;
/** 内部类提供给的写入锁 */
private final ReentrantReadWriteLock.WriteLock writerLock;
/** 持有的同步器 */
final Sync sync;
内部类
Sync

读写锁中维护的同步器

abstract static class Sync extends AbstractQueuedSynchronizer {
	//位偏移
	static final int SHARED_SHIFT   = 16;
    static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
    //最大锁数量65535
    static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
    //低16位,独占锁掩码
    static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

	//第一个读锁
	private transient Thread firstReader = null;
    private transient int firstReaderHoldCount;
    //当前线程持有的读锁数
    private transient ThreadLocalHoldCounter readHolds;
    //前一个成功获取读锁的线程持有的读锁数
    private transient HoldCounter cachedHoldCounter;
    //线程持有的计数器
    static final class HoldCounter {
        int count = 0;
        // Use id, not reference, to avoid garbage retention
        final long tid = getThreadId(Thread.currentThread());
    }
	
	//当前读写锁中读锁的数量
	static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
    //当前读写锁中写锁的数量
    static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }


	
}
获得读锁过程
  1. 如果同步器state的写锁数量不为0并且独占线程不为当前线程则当前线程进入同步器的竞争队列
  2. 判断是否满足获得读锁条件
    2.1. 读锁是否需要被阻塞(公平锁:竞争队列存在节点则返回false,非公平锁:第一个节点为写线程则返回false)
    2.2. 读锁数量是否超过上限(65535)
    2.3 CAS将同步器读锁数量+1
  3. 如果条件成立则设置当前线程持有读锁的数量 ,如果为第一个获取读锁的线程就设置firstReaderHoldCount否则设置ThreadLocal变量HoldCounter
  4. 如果条件不成立,则进入fullTryAcquireShared方法自旋再次尝试获得锁,再次失败进入同步器的竞争队列
//读锁尝试获得锁
protected final int tryAcquireShared(int unused) {
    Thread current = Thread.currentThread();
    int c = getState();
    //如果写锁数量不为0(state的低16位)并且独占线程不为当前线程的返回-1获取读锁失败
    if (exclusiveCount(c) != 0 &&
        getExclusiveOwnerThread() != current)
        return -1;
    //获得读锁数量
    int r = sharedCount(c);
    //非公平锁判断竞争队列头节点为写锁则返回false
    //公平锁判断竞争队列中是否存在节点,存在则返回false
    if (!readerShouldBlock() &&
        r < MAX_COUNT &&
        //CAS将读锁加1
        compareAndSetState(c, c + SHARED_UNIT)) {
        if (r == 0) {
        	//如果读锁为0,则设置第一个读为当前线程
        	//第一个读线程持有锁数量为1
            firstReader = current;
            firstReaderHoldCount = 1;
        } else if (firstReader == current) {
        	//如果第一个读线程为当前线程则将持有锁数量+1
            firstReaderHoldCount++;
        } else {
            HoldCounter rh = cachedHoldCounter;
            //rh未初始化或rh前一个获取读锁的线程的tid与当前线程不等
            if (rh == null || rh.tid != getThreadId(current))
                cachedHoldCounter = rh = readHolds.get();
            else if (rh.count == 0)
                readHolds.set(rh);
            rh.count++;
        }
        return 1;
    }
    //自旋再次尝试获取锁
    return fullTryAcquireShared(current);
}
获得写锁过程
  1. 判断当前同步器持有锁的数目
  2. 如果同步器持有锁
    2.1. 同步器持有的是读锁或持有写锁的线程不为当前线程,返回false,进入竞争队列
    2.2.如果超过最大锁数量则抛出异常
    2.3 设置state写锁数,返回true,获得锁成功
  3. 如果同步器无锁
    3.1. 判断写操作是否需要被阻塞(非公平锁:直接返回false,公平锁:如果竞争队列中存在节点则返回true
    3.2. 执行CAS操作修改state写锁数
protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState();
    int w = exclusiveCount(c);
    //当前同步器持有锁
    if (c != 0) {
        // 同步器持有的是读锁或持有写锁的线程不为当前线程
        if (w == 0 || current != getExclusiveOwnerThread())
            return false;
        //如果持有锁数量超过最大数量抛出异常
        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        // Reentrant acquire
        setState(c + acquires);
        return true;
    }
    //如果当前同步器没持有锁
    //不公平锁:writeShouldBlock返回false
    //公平锁:如果队列中存在节点则返回true
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false;
    setExclusiveOwnerThread(current);
    return true;
}
释放读锁过程
  1. 修改当前线程持有读锁数量
  2. 自旋修改读锁数,返回 读锁数==0
protected final boolean tryReleaseShared(int unused) {
    Thread current = Thread.currentThread();
    //如果当前线程为第一个获得读锁的线程
    if (firstReader == current) {
        if (firstReaderHoldCount == 1)
            firstReader = null;
        else
            firstReaderHoldCount--;
    } else {
    	//如果不为第一个则获得ThreadLocal中的计数器
        HoldCounter rh = cachedHoldCounter;
        if (rh == null || rh.tid != getThreadId(current))
            rh = readHolds.get();
        int count = rh.count;
        if (count <= 1) {
            readHolds.remove();
            if (count <= 0)
                throw unmatchedUnlockException();
        }
        --rh.count;
    }
    for (;;) {
        int c = getState();
        int nextc = c - SHARED_UNIT;
        if (compareAndSetState(c, nextc))
        	//释放读锁并不影响其他线程继续读取
        	//修改读锁数用于给写锁判断同步器是否持有锁
            return nextc == 0;
    }
}
释放写锁过程
  1. 修改同步器持有写锁数
protected final boolean tryRelease(int releases) {
	//判断独占访问权限线程是否为当前线程
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    //因为只有一个线程在执行当前代码,所以无需CAS修改state
    int nextc = getState() - releases;
    boolean free = exclusiveCount(nextc) == 0;
    //如果写锁数为0则设置独占访问权限线程为null
    if (free)
        setExclusiveOwnerThread(null);
    setState(nextc);
    return free;
}
StampedLock

jdk1.8之后引进的读写锁,不可重入,ReentrantReadWriteLock在读的情况不允许写操作,而StampedLock提供悲观读锁实现在读的过程中允许写操作。对于可能导致读的数据不一致,StampedLock提供了方法来验证读锁后是否有其他写锁发生。

private final StampedLock lock = new StampedLock();
void update(int i) {
	//获取写锁
    long stamp = lock.writeLock();
    try {
        this.i = i;
    } finally {
        lock.unlockWrite(stamp);
    }
}

int get() {
	//获取乐观读锁
    long stamp = lock.tryOptimisticRead();
    int value = i;
    //验证读取过程是否出现写入
    if (!lock.validate(stamp)) {
    	//出现写入则使用悲观读锁再次读取
        stamp = lock.readLock();
        try {
            value = i;
        } finally {
            lock.unlockRead(stamp);
        }
    }
    return value;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
后台采用apache服务器下的cgi处理c语言做微信小程序后台逻辑的脚本映射。PC端的服务器和客户端都是基于c语言写的。采用mysql数据库进行用户数据和聊天记录的存储。.zip C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值