上下文
:指的是寄存器数据和程序计数器
上下文切换
:指的是保存旧线程的上下文数据,加载新线程的上下文数据的动作
// the registers xv6 will save and restore
// to stop and subsequently restart a process
struct context {
int eip;
int esp;
int ebx;
int ecx;
int edx;
int esi;
int edi;
int ebp;
};
// the different states a process can be in
enum proc_state { UNUSED, EMBRYO, SLEEPING,
RUNNABLE, RUNNING, ZOMBIE };
// the information xv6 tracks about each process
// including its register context and state
struct proc {
char *mem; // Start of process memory
uint sz; // Size of process memory
char *kstack; // Bottom of kernel stack
// for this process
enum proc_state state; // Process state
int pid; // Process ID
struct proc *parent; // Parent process
void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
struct context context; // Switch here to run process
struct trapframe *tf; // Trap frame for the
// current interrupt
};
jstack的使用
作用
:在运行时获取Java虚拟机中线程的堆栈信息
语法
:jstack [HTML_REMOVED]
waiting for monitor entry
:等待获取锁
waiting on condition
:等待被唤醒
in Object.wait()
:获取锁后又执行Obj.wait()释放锁
资源限制
volatile
volatile保证了共享变量的可见性
:这里的可见性就是,一个线程修改了变量之后,其他的线程可以读到修改后的值
实现原理
1. Lock指令会使得处理器中的缓存回写到内存中
volatile的内存语义
Java中锁的作用
- 上锁的代码互斥执行
- 释放锁的线程向获取同一个锁的线程发送消息
锁释放和锁获取的内存语义
- 锁释放:线程的本地内存中的共享变量刷新到主内存中
- 锁获取:JMM把线程对应的本地内存置为无效,临界区代码必须从主内存中读取共享变量
Object的方法描述
- notify()
- notifyAll()
- wait():调用对象wait()方法的线程进入waiting状态,使线程进入了对象的等待队列
- wait(long waitTime)
- wait(long waitIime, int )
生产者消费者模式
消费者
synchronized(obj) {
while(flag == false) {
obj.wait();
}
dosomething();
}
生产者
****
synchronized(obj) {
flag = true;
obj.notifyAll();
}
join方法
线程A执行b.join():线程A等待b线程死亡才能从b.join()方法返回
t.join()方法只会使调用t.join()的线程进入等待池并等待t线程执行完毕后才会被唤醒。并不影响同一时刻处在运行状态的其他线程。
tip:t1.join()需要等t1.start()执行之后执行才有效果
join源码中,只会调用wait方法,并没有在结束时调用notify,这是因为线程在die的时候会自动调用自身的notifyAll方法,来释放所有的资源和锁。
t = new Thread(()->{});
1. t.join 方法会让调用这个方法的线程进入t线程对象的同步队列
2. 只有t先start再调用t.join()方法才会生效
3. 如果t.start(); t2.start(); t.join();并不会对t和t2之间的顺序产生影响,当执行了t.join()时,t2线程已经启动了,此时只会让main线程等待t结束,t2并不会阻塞因为t.join 方法会让调用这个方法的线程进入t线程对象的同步队列
synchronized和lock锁的比较
synchronized优点和缺点
优点:隐式的获取和释放锁
缺点:锁的使用不灵活
lock锁
优点:锁的使用更加灵活
缺点:需要手动的获取和释放锁
lock 接口的方法描述
/*
* 可以理解为阻塞的获取锁吗?
* 如果锁不可以被获取,当前线程将处于休眠状态直到锁可被获取
*/
void lock();
/*
* 成功获取锁
* 如果锁不可被获取,当前线程进入休眠状态,除非两种情况发生
* 1. 当前线程获取到了锁
* 2. 其他线程中断当前线程
*/
void lockInterruptibly() throws InterruptedException;
/*
** 非阻塞的获取锁
**当tryLock方法被调用的时候,当前锁可以被获取到则获取锁,并立刻返回一个true
** ,当前锁不可以被索取到锁的时候,立刻返回一个false
*/
boolean trylock();