串行与并发
串行:多任务按照顺序依次执行 ,就好比一条单行道,里面有很多车,
只要前车不前进,后面的车始终会被阻塞在那。
并发:多任务同时进行。 好比一条路有多条道,就可以同时通行多辆车。
程序与进程与线程
一个程序下至少有一个进程,一个进程下至少有一个线程
程序:是 一堆代码放在一个文件中 通常后缀为exe 原本是存储在硬盘上的
进程是 将代码从硬盘读取到内存然后执行 产生的
进程:是由程序产生的
一个程序可以产生多个进程,例如qq多开 每一个进程都具备一个PID 进程变编号 且是唯一的
线程:操作系统能够进行运算调度的最小单位,同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈,自己的寄存器环境,自己的线程本地存储
线程的生命周期
一个线程实例化完成,到销毁的过程
新生态: New
一个线程被实例化完成,但还没有任何操作
就绪态: Ready
一个线程已经被开启,正在争抢cpu时间片
运行态: Run
一个线程抢到了时间片,开始执行线程中的逻辑
阻塞态: Interrupt
线程执行过程中,收到某些操作影响,放弃了已获取的时间片,并且不在争抢cpu时间片,处于挂起状态
死亡态:
一个线程对象需要被销毁
线程的开辟方式
•继承 Thread 重写 run 方法;
•实现 Runnable 接口;
•实现 Callable 接口。
继承Thread方法:
public class MyThread2 implements Runnable {//实现Runnable接口
public void run(){
//重写run方法
}
}
public class Main {
public static void main(String[] args){
//创建并启动线程
MyThread2 myThread=new MyThread2();
Thread thread=new Thread(myThread);
thread().start();
//或者 new Thread(new MyThread2()).start();
}
}
代码可视性好,但不能继承别的类
实现Runnable接口:
public class MyThread2 implements Runnable {//实现Runnable接口
public void run(){
//重写run方法
}
}
public class Main {
public static void main(String[] args){
//创建并启动线程
MyThread2 myThread=new MyThread2();
Thread thread=new Thread(myThread);
thread().start();
//或者 new Thread(new MyThread2()).start();
t.start();
}
}
//另一种
Runnable r=()=>{
//线程
}
Thread t=new Thread(r,name:"cll");
可以继承其他类
线程的常用方法
//获取当前线程的名字
Thread.currentThread().getName()
1.start():1.启动当前线程2.调用线程中的run方法
2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程的名字
5.setName():设置当前线程的名字
6.yield():主动释放当前线程的执行权
7.join():在线程中插入执行另一个线程,该线程被阻塞,直到插入执行的线程完全执行完毕以后,该线程才继续执行下去
8.stop():过时方法。当执行此方法时,强制结束当前线程。
9.sleep(long millitime):线程休眠一段时间
10.isAlive():判断当前线程是否存活
临界资源问题
多线程执行过程中,线程争抢cup时间片,a线程还没执行完毕,b线程就抢夺了cpu,执行过程中经常发生,咋成紊乱,
解决办法: 在方法或代码块中加上同步锁或显示锁
上锁之后,所有经过此方法的线程到锁池领取锁标记,排队执行线程,只能等一个线程执行完毕,才会执行下一个线程
同步锁(syncrhonized)
public class ThreadSafe {
public static Object obj = new Object();
public static void main(String[] args) {
MyThread t1 = new MyThread("窗口一");
MyThread t2 = new MyThread("窗口一");
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class MyThread extends Thread{
private static int count = 10;
public MyThread(String name) {
super(name);
}
@Override
public void run() {
while(count > 0) {
//静态代码块锁,定义同一个对象
synchronized (obj) {
System.out.println(Thread.currentThread().getName()+"售出:"+(count--) +" 票");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
显示锁ReenTrant(手动锁lock())
//使用类锁
public class ThreadSafe3 {
public static Lock lock = new ReentrantLock();
public static void main(String[] args) {
MyThread t1 = new MyThread("窗口一");
MyThread t2 = new MyThread("窗口二");
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class MyThread extends Thread{
private static int count = 10;
public MyThread(String name) {
super(name);
}
public static void increase() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"售出:"+(count--) +" 票");
}catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
@Override
public void run() {
while(count > 0) {
//静态代码块锁,定义同一个对象
increase();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
死锁
两个线程分别持有对方需要的锁资源,互不释放,一直僵持了下去。
解决办法: a.wait让其中一个线程释放,执行完另一个线程在a.notify唤醒线程。
public class DeadLockDemo {
public static void main(String[] args) {
// 线程a
Thread td1 = new Thread(new Runnable() {
public void run() {
DeadLockDemo.method1();
}
});
// 线程b
Thread td2 = new Thread(new Runnable() {
public void run() {
DeadLockDemo.method2();
}
});
td1.start();
td2.start();
}
public static void method1() {
synchronized ("a") {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程a尝试获取integer.class");
//在这个地方释放
a.wait();
synchronized ("b") {
}
System.out.println("线程a已经获取integer.class"); //这条语句没有执行
}
}
public static void method2() {
synchronized ("b") {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程b尝试获取String.class");
synchronized ("a") {
}
System.out.println("线程b已经获取String.class"); //这条语句没有执行
执行完
a.notify();
}
}
}
----------------
线程b尝试获取String.class
线程a尝试获取integer.class
....
...
..
.
无限阻塞下去
多线程环境下的懒汉模式
public class ll {
public static void main(String[] args) {
for (int i = 0; i < 1000000000; i++) {
lanh.getlanhan();
}
}
}
class lanh{
private lanh() {
System.out.println("我是懒汉");
}
private static lanh lh=null;
public static synchronized lanh getlanhan() {
if(lh==null) {
lh=new lanh();
}
return lh;
}
}
cpu多核并发缓存架构刨析
总线加锁
volatile
保证多线程间共享变量的可见性
MESI缓存一致性协议
当store出来的数据接触到总线时,锁住主内存中对应的数据,等到将对应的数据重新赋值后,解锁另一个cpu再取数据