多线程详解

串行与并发

串行与并发

串行:多任务按照顺序依次执行 ,就好比一条单行道,里面有很多车,

只要前车不前进,后面的车始终会被阻塞在那。

并发:多任务同时进行。 好比一条路有多条道,就可以同时通行多辆车。

程序与进程与线程

一个程序下至少有一个进程,一个进程下至少有一个线程
程序:是 一堆代码放在一个文件中 通常后缀为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再取数据
在这里插入图片描述

学习方向

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值