多线程
一个进程便是一个正在运转的程序。
线程便是进程中的履行单位。
一个进程里能够有多个线程故而称之为多线程(一个线程只归于一个进程)。
线程履行相当于去抢cpu履行的,当履行一个线程未履行完事或许下一个线程开端履行了。
线程创立
java中线程创立的办法有两种:一种是集成Thread类,如果类承继了Thread类那么这个类就被成为线程类,一种是完结接口
承继Thread类
承继Thread类有必要完结run办法。
创立了几个线程类目标就相当于有几个线程
启用线程有必要运用start办法
线程类的常用办法
start() 启用线程
setName() 线程命名
getName() 获取线程名称
public class ThreadDemo extend Thread{
public void run(){
for(int i=0;i<100;i++){
System.out.println(getName()+i);
}
}
}
public class void test(){
public static void main(String[] aargs){
//创立线程类目标,创立几个线程类目标相当于几个线程
ThreadDemo threadDemo=new ThreadDemo();
threadDemo.setName("线程1");
threadDemo.setName("线程2");
ThreadDemo threadDemo2=new ThreadDemo();
//启用线程
threadDemo.start();
threadDemo2.start();
}
}
完结Runnable接口
完结Runnable是完结的run 办法,运用runnable的优点便是能够操作多个线程之间数据的同享
public class RunnableDemo implements Runnable{
public void run(){
for(int i=0;i<100;i++){
System.out.peintln(Thread.currentThread().getName());
}
}
}
public class test{
public static void main(String[] args){
RunnableDemo runnableDemo=new RunnableDemo();
//敞开线程需求转Threa目标
ThreaD thread=new Thread(runnableDemo);
thread.start();
}
}
线程的履行状况
线程是有生命周期的
new Thread(创立线程类目标) 线程重生
start(启动线程) 线程预备期
cpu分配 运转状况 当cpu分配给哪个线程,线程便是运转状况
当线程未履行完,cpu被分配给其他线程,那么当时的线程进入预备状况,等候cpu分配
当线程履行完毕 线程进入死亡状况
当cpu分配给线程时,线程被其他要素终端,线程进入堵塞状况,当线程堵塞完毕延时堵塞完毕后进入预备状况等候持续履行。
当线程进入堵塞状况时,cpu则会被分配给其他线程
多线程高并发和并行
高并发便是一段时间内cpu履行多个线程
并行便是同一时刻多个线程一起履行(并行只发生在多cpu的状况下)
线程调度
线程优先级
经过setPriority进行设置线程优先级,参数是0-10数字越大优先级越高,默许线程的优先级是5 ,设置优先级仅仅能够保证线程的邮优先级,并不能完全保证线程仍是随机的。
join办法也能够进行优先级的进步。在线程敞开之后调用该线程的join办法那么其他线程就需求等候当时敞开join的线程先履行完
yield yield办法是礼让一般在run办法中调用便是先暂停当时线程的履行,礼让给其他线程
sleep 线程睡眠,参数是毫秒
setDaomon 看护线程,看护线程便是当其他线程履行完结之后,看护线程完毕。
public RunableDemo1 implments Runnable{
public void run(){
for(int i=0;i<100;i++){
System.out.println(1);
}
}
}
public class test {
public static void main(String[] args){
RunnableDemo1 demo1=new RunnableDemo1();
RunnableDemo1 demo2=new RunnableDemo1();
demo1.setPriotirty(10);
demo2.setPriotirty(1);
demo1.start();
demo2.start();
//demo1先运转的机率比demo2的概率大
}
}
线程安全
线程锁
经过关键字能够保证代码履行完结之后才能被下一个进程履行
synchornized 关键字
这个关键字也能够写到办法上
//同步代码块,同步代码块需求添加锁,保证不同进程操作的锁是相同的
public class ThreadDemo implements Runnable{
private int num=100;
private Object obj=new Object();
@Override
public void run() {
while(true){
synchronized (obj){
if(num > 0){
System.out.println(Thread.currentThread().getName()+"卖了"+num+"票");
this.num--;
}else{
break;
}
}
}
}
}
//锁办法,锁办法的话那么当时的锁便是this
public class ThreadDemo implements Runnable{
private int num=100;
private Object obj=new Object();
@Override
public void run() {
while(true){
test();
}
}
public synchronized void test(){
if(num > 0){
System.out.println(Thread.currentThread().getName()+"卖了"+num+"票");
this.num--;
}
}
}
//静态办法锁,静态办法锁的锁是当时的类
public class ThreadDemo implements Runnable{
public static int num=100;
private Object obj=new Object();
@Override
public void run() {
while(true){
test();
}
}
public synchronized static void test(){
if(ThreadDemo.num > 0){
System.out.println(Thread.currentThread().getName()+"卖了"+num+"票");
num--;
}
}
}
Lock锁
Lock便是一个同步锁的笼统类。
Lock的完结类
有两个办法 lock() 加锁
unlock() 完毕锁
死锁
避免死锁出现的状况,便是避免运用同步锁嵌套
线程通讯
线程通讯是经过wait和notify办法,java的线程通讯其实的本质便是经过同步锁操作同一个目标,然后便是wait等候和notify唤醒
//包子类
package com.Thread.Emaile;
public class Bzozi {
private String pi;
private String x;
private boolean bl=false;
public String getPi() {
return pi;
}
public void setPi(String pi) {
this.pi = pi;
}
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
public boolean isBl() {
return bl;
}
public void setBl(boolean bl) {
this.bl = bl;
}
}
//包子铺线程
public class Bozipu extends Thread{
public Bzozi bz;
public int count=0;
public Bozipu(Bzozi bz){
this.bz=bz;
}
@Override
public void run() {
while(true){
synchronized (bz){
test();
}
}
}
public void test(){
if(bz.isBl() == true){
try {
//如果有包子,那么包子铺线程等候,包子被吃
bz.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//没有包子开端做包子
if(count %3 ==1){
bz.setPi("杂粮皮");
bz.setX("猪肉大葱");
bz.setBl(true);
}else if(count%3 == 0){
bz.setPi("巧克力脆皮");
bz.setX("韭菜鸡蛋");
bz.setBl(true);
}else{
bz.setPi("抹茶");
bz.setX("奶油");
bz.setBl(true);
}
count++;
System.out.println("包子做好了,吃货能够来吃了");
bz.notify(); //唤醒吃货
}
}
//吃货线程
package com.Thread.Emaile;
public class Eat extends Thread{
public Bzozi bz;
public Eat(Bzozi bz){
this.bz=bz;
}
@Override
public void run() {
while(true){
synchronized (bz){
test();
}
}
}
public void test(){
//没有包子,等候包子铺做包子
if(bz.isBl() == false){
try {
bz.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("正在吃"+bz.getPi()+"皮"+bz.getX()+"馅的包子");
bz.setBl(false);
bz.notify();
}
}
//test
/**
* 吃包子的事例便是用bz来做锁
* 不论哪个线程先履行,如果是包子铺先履行,没有包子的话就做,做完之后唤醒吃货,有就等候吃货吃完之后再唤醒包子铺去做
* 如果是吃货先履行,那有就吃,没有就唤醒包子铺做
*/
public class test {
public static void main(String[] args) {
Bzozi bz=new Bzozi();
Thread eat=new Eat(bz);
Thread bzp=new Bozipu(bz);
eat.start();bzp.start();
}
}
线程池
线程池的优点便是能够循环往复的利用线程。下降资源耗费,削减线程的创立和销毁
线程池运用
线程池的顶级接口 是Executor 可是并不是真正的线程池,仅仅一个履行现成的工具,线程池的完结接口 是ExecutorService。
详细完结类
ThreadPoolExecutor 运用或许的几个合并的线程履行每个提交的使命,一般运用Exceutor
public class test {
public static void main(String[] args) {
//利用静态办法获取完结类
ExecutorService executor= Executors.newFixedThreadPool(2);
//能够看到需求跑的使命有6个可是只要两个线程,所以两个线程替换履行
Thread thread=new Thread(new ThreadDemo());
executor.submit(thread);
executor.submit(thread);
executor.submit(thread);
executor.submit(thread);
executor.submit(thread);
executor.submit(thread);
//封闭线程池
executor.shutdown();
}
}
Volatile关键字
首要需求了解可见性,可见性是一种复杂的特点。可见性,是指线程之间的可间性,便是一个线程修正的状况关于另外一个线程是可见的。所以需求用到volatile关键字来润饰变量,volatile关键字保证了变量的可见性。volatile关键字润饰的变量不允许线程内部缓存和重排序,即直接修正内存,所以对其他线程是可见的,可是volatile只能保证可见性,不能保证原子性,比方直接赋值这种便是保证了原子性运用了原子操作,可是运用a++便是一个非原子操作仍然存在线程安全的问题。
原子性:原子性是世界上最小的单位,具有不可切割性,比方a=10是不可切割的是一个原子操作,1=a+1是能够切割的所以不是一个原子操作,非原子操作都会存在线程安全问题,所以需求运用同步锁完结原子操作
volatile的原理
volatile是java供给的一种稍弱的同步机制,即vloatile变量,用来保证变量的更新操作能够告诉到其他线程,当把变量声明为volatile类型后,编译器与运转时都会注意到这个变量是同享的,因而不会将该变量的操作与与其他内存一起重排序。
在拜访volatile变量时不会履行桎梏操作,因而也就不会使履行线程堵塞,因而volatile是一种比sychronized更轻量级的同步机制
当变量被volatile关键字润饰时,jvm保证了每次读变量都存内存中读取,跳过cpu缓存这一步
当一个变量被定义为volatile之后,将具有两种特性
对一切线程的可见性以及制止指令重排序优化
volatile的变量的读性能与一般变量简直相同,可是写的操作稍慢,因为需求在本地代码中刺进许多内存屏障指令来保证处理器不发生乱序行为。
规划形式
规划形式分类
规划形式分为三类: 创立型形式 结构型形式 行为型形式
创立型形式
创立型形式便是将目标的创立与运用别离
单例,原型,工厂办法,笼统工厂,制作者形式
结构型形式
结构型形式便是将类或者目标按照某种布局组成更大的结构
署理,适配器,桥接,装修,外观,享元,组合
行为型形式
行为型形式便是用于描绘,类或者目标之间怎样互相协作共同完结单个目标无法独自完结的使命
模板办法
策略
命令
职责链
状况(状况机形式能够参阅promise)
观察者(vue里的数据响应便是运用了观察者形式)
中介者
迭代器
拜访者
备忘录形式
单例形式
单例形式是最简略的规划形式之一,归于创立型形式,这种形式涉及到一个单一的类,该类负责创立自己的目标。一起保证只要一个目标被创立,供给拜访其仅有目标的办法,能够直接拜访,不被实例化。
单例形式步骤
私有化结构办法
在当时类中供给一个输出该类目标的办法
懒汉单例形式(线程不安全)
第一次获取目标的时分才会进行赋值,节省资源
处理懒汉形式的线程安全问题便是加锁,既保证安全又需求保证效率就运用锁+线程
饿汉形式-单例形式(急加载)
该类第一次被拜访时立即创立目标 。不存在线程安全问题
缺陷: 资源占用大,资源糟蹋
原型(Prootype)形式
原型形式便是将一个目标作为原型,经过对其进行赋值而克隆出多个和原型类似的新实例
工厂形式
统一管理某个类的创立
简略工厂类 运用静态办法
public class Facetory implements Animals{
// 静态工厂形式
private static Map<String,Thacher> storeMap;
public static void init(){
storeMap=new HashMap<String,Thacher>();
storeMap.put("t1",new Thacher("张三","男",20));
storeMap.put("t2",new Thacher("李四","男",21));
storeMap.put("t3",new Thacher("王五","男",22));
}
public static Thacher getTeacher(String key){
return storeMap.get(key);
}
}
实例工厂办法 不加静态
public class Facetory implements Animals{
private Map<String,Thacher> storeMap;
public Facetory(){
storeMap=new HashMap<String,Thacher>();
}
public Thacher getTeacher(String key){
return storeMap.get(key);
}
}
//test
Facetory facetory=new Facetory();
Thacher t1=facetory.getTeacher("t1");
System.out.println(t1.getName());
模板形式
模板形式便是在类里写一个笼统办法,笼统办法的完结在运用的时分写
//ModelDemo
public abstract class ModelDemo {
public double js(double a,double b){
double dl=ys(a,b);
System.out.println("运算结果是"+dl);
return dl;
}
public abstract double ys(double a,double b);
}
//test
public class test {
public static void main(String[] args) {
double dl=new ModelDemo(){
@Override
public double ys(double a, double b) {
return a*b;
}
}.js(18,21);
}
}
装修形式
对原有功用的增强,装修形式便是,在装修类里,调用原有的功用并且履行新的功用
// zq
public class zQ {
private Object obj;//要增强的目标
public zQ() {
}
public zQ(Object obj){
this.obj=obj;
}
public void zq(){
System.out.println("看视频");
System.out.println("看电子书");
if(obj instanceof Phone){
((Phone) this.obj).call();
}
}
}
//test
public class test {
public static void main(String[] args) {
zQ zq=new zQ(new Phone());
zq.zq();
}
}
面向目标思想规划准则
单一工作准则 高内聚,低耦合,一个类只要一个功用,
开闭准则,对扩展进行敞开,对修正进行封闭
里氏替换准则,同一个承继系统中的目标应该有共同的行为特征
依靠注入准则
依靠笼统类,不要依靠于详细完结
接口别离准则
一个接口只供给一种对外的功用
迪米特准则
下降目标之间的耦合,进步可维护性