进程的观点 : 运用程序(typerpa,word,IDEA)运行的时候进入到内存,程序在内存中占用的内存空间(进程).

1.2 线程

线程(Thread) : 在内存和CPU之间,建立一条连接通路,CPU可以到内存中取出数据进行打算,这个连接的通路,便是线程.

一个内存资源 : 一个独立的进程,进程中可以开启多个线程 (多条通路)

php多线程假死java多线程线程同步与线程池超具体讲授 AJAX

并发: 同一个时候多个线程同时操作了同一个数据

并行: 同一个时候多个线程同时实行不同的程序

2. Java实现线程程序

本日之前的所有程序都有一个共性 : main启动之后,一条线走到底 (单线程)

2.1 java.lang.Thread类

统统都是工具,线程也是工具,Thread类是线程工具的描述类

实现线程程序的步骤 :定义类继续Thread子类重写方法run创建子类工具调用子类工具的方法start()启动线程

//- 定义类继续Thread//- 子类重写方法runpublic class SubThread extends Thread { public void run(){ for(int x = 0 ; x < 50 ;x++) System.out.println("run..."+x); }}public static void main(String[] args) { //创建线程程序 SubThread subThread = new SubThread(); //调用子类工具的方法start()启动线程 //启动线程,JVM调用方法run subThread.start(); for(int x = 0 ; x < 50 ;x++) System.out.println("main..."+x);}2.2 线程的内存图

2.3 Thread类方法Thread类的方法 getName()返回线程的名字,返回值是String类型

public class ThreadName extends Thread { public void run (){ System.out.println("线程名字:: "+ super.getName()); }} public static void main(String[] args) { ThreadName threadName = new ThreadName(); //threadName.setName("旺财"); threadName.start(); ThreadName threadName1 = new ThreadName(); //threadName1.setName("小强"); threadName1.start(); }Thread类静态方法 : Thread currentThread()静态调用,浸染是返回当前的线程工具"当前" , 当今皇上. 本地主机

//获取当前哨程工具,拿到运行main方法的线程工具Thread thread = Thread.currentThread();System.out.println("name::"+thread.getName());Thread类的方法 join()阐明,实行join()方法的线程,他不绝止,其它线程运行不了

public static void main(String[] args) throws InterruptedException { JoinThread t0 = new JoinThread(); JoinThread t1 = new JoinThread(); t0.start(); t0.join(); t1.start(); }Thread类的方法 static yield()线程让步,线程把实行权让出

public void run() { for(int x = 0 ; x < 50 ;x++){ Thread.yield(); System.out.println(Thread.currentThread().getName()+"x.."+x); } }3. Java实现线程程序3.1 java.lang.Runnable接口实现线程程序的步骤 :定义类实现接口重写接口的抽象方法run()创建Thread类工具Thread类布局方法中,通报Runnable接口的实现类工具调用Thread工具方法start()启动线程

//- 定义类实现接口// - 重写接口的抽象方法run()public class SubRunnable implements Runnable{ @Override public void run() { for(int x = 0 ; x < 50 ;x++){ System.out.println(Thread.currentThread().getName()+"x.."+x); } }} public static void main(String[] args) { //创建接口实现类工具 Runnable r = new SubRunnable(); //创建Thread工具,布局方法通报接口实现类 Thread t0 = new Thread(r); t0.start(); for(int x = 0 ; x < 50 ;x++){ System.out.println(Thread.currentThread().getName()+"x.."+x); } }3.2 实现接口的好处

接口实现好处是设计上的分离效果 : 线程要实行的任务和线程工具本身是分离的.

继续Thread重写方法run() : Thread是线程工具,run()是线程要实行的任务

实现Runnable接口 : 方法run在实现类,和线程无关,创建Thread类通报接口的实现类工具,线程的任务和Thread没有联系, 解开耦合性

4. 线程安全

涌现线程安全的问题须要一个条件 : 多个线程同时操作同一个资源

线程实行调用方法run,同一个资源是堆内存的

4.1 售票例子

火车票的票源是固定的,购买渠道在火车站买,n多个窗口

/ 票源工具,须要多个线程同时操作 /public class Ticket implements Runnable { //定义票源 private int tickets = 100; @Override public void run() { while (true) { if (tickets > 0) { try { Thread.sleep(10);//线程休眠,停息实行 }catch (Exception ex){} System.out.println(Thread.currentThread().getName()+" 出售第" + tickets + "张"); tickets--; }else break;; } }}public static void main(String[] args) { Ticket ticket = new Ticket(); //创建3个窗口,3个线程 Thread t0 = new Thread(ticket); Thread t1 = new Thread(ticket); Thread t2 = new Thread(ticket); t0.start(); t1.start(); t2.start();}

办理线程的安全问题 : 当一个线程没有完玉成体操作的时候,其它线程不能操作

4.2 同步代码

同步代码块可以办理线程安全问题 : 格式 synchronized关键字

synchronized(任意工具){ //线程操作的共享资源}

任意工具 : 在同步中这个工具称为工具锁,简称锁,官方的文档称为 工具监视器

同步代码块,如何担保线程的安全性.

同步代码块的实行事理 : 关键点便是工具锁线程实行到同步,判断锁是否存在如果锁存在,获取到锁,进入到同步中实行实行完毕,线程出去同步代码块,讲锁工具归还线程实行到同步,判断锁所否存在如果锁不存在,线程只能在同步代码块这里等待,锁的到来

利用同步 : 线程要先判断锁,然后获取锁,出去同步要开释锁, 增加了许多步骤,因此线程安全运行速率慢. 捐躯性能,不能捐躯数据安全

4.3 同步方法

当一个方法中,所有代码都是线程操作的共享内容,可以在方法的定义上添加同步的关键字 synchronized , 同步的方法,或者称为同步的函数.

同步方法中有工具锁吗 , this工具静态同步方法中有工具锁吗,锁工具是本类.class属性. 这个属性表示这个类的class文件的工具.

@Override public void run() { while (true) sale(); }private static synchronized void sale(){ // synchronized (Ticket.class) { if (tickets > 0) { try { Thread.sleep(20);//线程休眠,停息实行 } catch (Exception ex) { } System.out.println(Thread.currentThread().getName() + " 出售第" + tickets + "张"); tickets--; }// }}5. 去世锁

去世锁程序 : 多个线程同时争夺同一个锁资源,涌现程序的假去世征象.

口试点 : 稽核开拓职员是否充分理解同步代码的实行事理

同步代码块 : 线程判断锁,获取锁,开释锁,不出代码,锁不开释

完成去世锁的案例 : 同步代码块的嵌套

去世锁代码

/ 实现去世锁程序 /public class ThreadDeadLock implements Runnable{ private boolean flag ; public ThreadDeadLock(boolean flag){ this.flag = flag; } @Override public void run() { while (true){ //同步代码块的嵌套 if (flag){ //前辈入A锁同步 synchronized (LockA.lockA){ System.out.println("线程获取A锁"); //在进入另一个同步B锁 synchronized (LockB.lockB){ System.out.println("线程获取B锁"); } } }else { //前辈入B锁同步 synchronized (LockB.lockB){ System.out.println("线程获取B锁"); //再进入另一个同步锁A锁 synchronized (LockA.lockA){ System.out.println("线程获取A锁"); } } } } }}public class LockA { public static LockA lockA = new LockA();}public class LockB { public static LockB lockB = new LockB();} public static void main(String[] args) { ThreadDeadLock threadDeadLock = new ThreadDeadLock(true); ThreadDeadLock threadDeadLock2 = new ThreadDeadLock(false); new Thread(threadDeadLock).start(); new Thread(threadDeadLock2).start(); }6. JDK5新特性Lock锁

JDK5新的特性 : java.util.concurrent.locks包. 定义了接口Lock.

Lock接口替代了synchronized,可以更加灵巧

Lock接口的方法void lock() 获取锁void unlock()开释锁

Lock接口的实现类ReentrantLock

/ 优化为juc包的接口Lock /public class Ticket implements Runnable { //定义票源 private int tickets = 100; //获取Lock接口的实现类工具 private Lock lock = new ReentrantLock(); @Override public void run() { while (true) sale(); } private void sale(){ //获取锁 lock.lock(); if (tickets > 0) { try { Thread.sleep(20);//线程休眠,停息实行 } catch (Exception ex) { } System.out.println(Thread.currentThread().getName() + " 出售第" + tickets + "张"); tickets--; } //开释锁 lock.unlock(); }}7. 生产者与消费者

创建2个线程,一个线程表示生产者,另一个线程表示消费者

/ 定义资源工具 成员 : 产生商品的计数器 标志位 /public class Resource { int count ; boolean flag ;}/ 生产者线程 资源工具中的变量++ /public class Produce implements Runnable{ private Resource r ; public Produce(Resource r) { this.r = r; } @Override public void run() { while (true){ synchronized (r) { //判断标志位,是否许可生产 //flag是true,生产完成,等待消费 if (r.flag ) //无限等待 try{ r.wait(); }catch (Exception ex){} r.count++; System.out.println("生产第" + r.count + "个"); //修正标志位,已经生产了,须要消费 r.flag = true; //唤醒消费者线程 r.notify(); } } }}/ 消费者线程 资源工具中的变量输出打印 /public class Customer implements Runnable{ private Resource r ; public Customer(Resource r) { this.r = r; } @Override public void run() { while (true){ synchronized (r) { //是否要消费,判断标志位 ,许可消费才能实行 if (!r.flag ) //消费完成,不能再次消费,等待生产 try{r.wait();}catch (Exception ex){} System.out.println("消费第" + r.count); //消费完成后,修正标志位,变成已经消费 r.flag = false; //唤醒生产线程 r.notify(); } } }}public static void main(String[] args) { Resource r = new Resource(); //接口实现类,生产的,消费的 Produce produce = new Produce(r); Customer customer = new Customer(r); //创建线程 new Thread(produce).start(); new Thread(customer).start();}线程通信的方法 wait() notify()方法的调用必须写在同步中调用者必须是作为锁的工具wait(),notify()为什么要定义在Object类同步中的锁,是任意工具,任何类都继续Object

案例改为方法实现

/ 定义资源工具 成员 : 产生商品的计数器 标志位 /public class Resource { private int count ; private boolean flag ; //消费者调用 public synchronized void getCount() { //flag是false,消费完成,等待生产 if (!flag) //无限等待 try{this.wait();}catch (Exception ex){} System.out.println("消费第"+count); //修正标志位,为消费完成 flag = false; //唤醒对方线程 this.notify(); } //生产者调用 public synchronized void setCount() { //flag是true,生产完成,等待消费 if (flag) //无限等待 try{this.wait();}catch (Exception ex){} count++; System.out.println("生产第"+count+"个"); //修正标志位,为生产完成 flag = true; //唤醒对方线程 this.notify(); }}/ 消费者线程 资源工具中的变量输出打印 /public class Customer implements Runnable{ private Resource r ; public Customer(Resource r) { this.r = r; } @Override public void run() { while (true) { r.getCount(); } }}/ 生产者线程 资源工具中的变量++ /public class Produce implements Runnable{ private Resource r ; public Produce(Resource r) { this.r = r; } @Override public void run() { while (true) { r.setCount(); } }}//测试类package thread.thread09;public class ThreadTest { public static void main(String[] args) {// 接口实现类,生产者,消费者 Resource r = new Resource(); Produce produce = new Produce(r); Customer customer=new Customer(r);// 创建线程 new Thread(produce).start();// Produce produce1=new Produce(r);// Thread t1=new Thread(produce1);// t1.start();跟上边效果相同 new Thread(customer).start(); }}7.1 安全问题产生线程本身便是一个新创建的方法栈内存 (CPU进来读取数据)线程的notify(),唤醒第一个等待的线程办理办法 : 全部唤醒 notifyAll()

被唤醒线程,已经进行过if判断,一旦醒来连续实行线程被唤醒后,不能急速就实行,再次判断标志位,利用循环while(标志位) 标志位是true,永久也出不去

/ 定义资源工具 成员 : 产生商品的计数器 标志位 /public class Resource { private int count ; private boolean flag ; //消费者调用 public synchronized void getCount() { //flag是false,消费完成,等待生产 while (!flag) //无限等待 try{this.wait();}catch (Exception ex){} System.out.println("消费第"+count); //修正标志位,为消费完成 flag = false; //唤醒对方线程 this.notifyAll(); } //生产者调用 public synchronized void setCount() { //flag是true,生产完成,等待消费 while (flag) //无限等待 try{this.wait();}catch (Exception ex){} count++; System.out.println("生产第"+count+"个"); //修正标志位,为生产完成 flag = true; //唤醒对方线程 this.notifyAll(); }}/ 生产者线程 资源工具中的变量++ /public class Produce implements Runnable{ private Resource r ; public Produce(Resource r) { this.r = r; } @Override public void run() { while (true) { r.setCount(); } }}/ 消费者线程 资源工具中的变量输出打印 /public class Customer implements Runnable{ private Resource r ; public Customer(Resource r) { this.r = r; } @Override public void run() { while (true) { r.getCount(); } }} public static void main(String[] args) { Resource r = new Resource(); //接口实现类,生产的,消费的 Produce produce = new Produce(r); Customer customer = new Customer(r); //创建线程 new Thread(produce).start(); new Thread(produce).start(); new Thread(produce).start(); new Thread(produce).start(); new Thread(produce).start(); new Thread(produce).start(); new Thread(customer).start(); new Thread(customer).start(); new Thread(customer).start(); new Thread(customer).start(); new Thread(customer).start(); new Thread(customer).start(); }

7.2 线程方法sleep和wait的差异sleep在休眠的过程中,同步锁不会丢失 ,不开释wait()等待的时候,发布监视器的所属权, 开释锁.唤醒后要重新获取锁,才能实行7.3 生产者和消费者案例性能问题

wait()方法和notify()方法, 本地方法调用OS的功能,和操作系统交互,JVM找OS,把线程停滞. 频繁等待与唤醒,导致JVM和OS交互的次数过多.

notifyAll()唤醒全部的线程,也摧残浪费蹂躏线程资源,为了一个线程,不得以唤醒的了全部的线程.

7.4 Lock接口深入

Lock接口更换了同步synchronized, 供应了更加灵巧,性能更好的锁定操作

Lock接口中方法 : newCondition() 方法的返回值是接口 : Condition

[外链图片转存失落败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PHlspTLg-1638013498872)(img/线程壅塞行列步队.JPG)]

7.5 生产者与消费者改进为Lock接口Condition接口 (线程的壅塞行列步队)进入行列步队的线程,开释锁出去行列步队的线程,再次的获取锁接口的方法 : await() 线程开释锁,进入行列步队接口的方法 : signal() 线程出去行列步队,再次获取锁

线程的壅塞行列步队,依赖Lock接口创建

/ 改进为高性能的Lock接口和线程的壅塞行列步队 /public class Resource { private int count ; private boolean flag ; private Lock lock = new ReentrantLock();//Lock接口实现类工具 //Lock接口锁,创建出2个线程的壅塞行列步队 private Condition prod = lock.newCondition();//生产者线程壅塞行列步队 private Condition cust = lock.newCondition();//消费者线程壅塞行列步队 //消费者调用 public void getCount() { lock.lock();//获取锁 //flag是false,消费完成,等待生产 while (!flag) //无限等待,消费线程等待,实行到这里的线程,开释锁,进入到消费者的壅塞行列步队 try{cust.await();}catch (Exception ex){} System.out.println("消费第"+count); //修正标志位,为消费完成 flag = false; //唤醒生产线程行列步队中的一个 prod.signal(); lock.unlock();//开释锁 } //生产者调用 public void setCount() { lock.lock();//获取锁 //flag是true,生产完成,等待消费 while (flag) //无限等待,开释锁,进入莅临盆线程行列步队 try{prod.await();}catch (Exception ex){} count++; System.out.println("生产第"+count+"个"); //修正标志位,为生产完成 flag = true; //唤醒消费者线程壅塞行列步队中年的一个 cust.signal(); lock.unlock();//开释锁 }}

测试类:

package thread.thread11;public class test { public static void main(String[] args) { Res res = new Res(); Pro pro = new Pro(res); Cust cust = new Cust(res); Thread t0 = new Thread(pro); t0.setName("生产者1号"); Thread t1 = new Thread(pro); t1.setName("生产者2号"); Thread t2 = new Thread(pro); t2.setName("生产者3号"); Thread t3=new Thread(cust); t3.setName("消费者1号"); Thread t4=new Thread(cust); t4.setName("消费者2号"); Thread t5=new Thread(cust); t5.setName("消费者3号"); t0.start(); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); }}7.6 Lock锁的实现事理

利用技能不开源,技能的名称叫做轻量级锁

利用的是CAS锁 (Compare And Swap) 自旋锁

JDK限定 : 当竞争的线程大于即是10,或者单个线程自旋超过10次的时候

JDK逼迫CAS锁取消.升级为重量级锁 (OS锁定CPU和内存的通信总线)

[外链图片转存失落败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i7BL35SY-1638013498875)(img/CAS锁.JPG)]

8. 单例设计模式

设计模式 : 不是技能,因此前的人开拓职员,为理解决某些问题实现的写代码的履历.

所有的设计模式核心的技能,便是面向工具.

Java的设计模式有23种,分为3个种别,创建型,行为型,功能型

8.1 单例模式

哀求 : 担保一个类的工具在内存中的唯一性

实现步骤私有润色布局方法自己创建自己的工具方法get,返回本类工具

/ - 私有润色布局方法 - 自己创建自己的工具 - 方法get,返回本类工具 /public class Single { private Single(){} //饿汉式 private static Single s = new Single(); // 自己创建自己的工具// 方法get,返回本类工具 public static Single getInstance(){ return s; }}public static void main(String[] args) { //静态方法,获取Single类的工具 Single instance = Single.getInstance(); System.out.println("instance = " + instance); }

实现步骤

私有润色布局方法创建本类的成员变量, 不new工具方法get,返回本类工具

/ - 私有润色布局方法 - 创建本类的成员变量, 不new工具 - 方法get,返回本类工具 /public class Single { private Single(){} //

public static Single getInstance(){ synchronized (Single.class) { //判断变量s,是null就创建 if (s == null) { s = new Single(); } } return s; }

性能问题 : 第一个线程获取锁,创建工具,返回工具. 第二个线程调用方法的时候,变量s已经有工具了,根本就不须要在进同步,不要在判断空,直接return才是最高效的.双重的if判断,提高效率 Double Check Lock

private static volatile Single s = null; public static Single getInstance(){ //再次判断变量,提高效率 if(s == null) { synchronized (Single.class) { //判断变量s,是null就创建 if (s == null) { s = new Single(); } } } return s; }8.3 关键字volatile

成员变量润色符,不能润色其它内容

关键字浸染 :担保被润色的变量,在线程中的可见性防止指令重排序单例的模式, 利用了关键字,不该用关键字,可能线程会拿到一个尚未初始化完成看的工具(半初始化)

public class MyRunnable implements Runnable { private volatile boolean flag = true; @Override public void run() { m(); } private void m(){ System.out.println("开始实行"); while (flag){ } System.out.println("结束实行"); } public void setFlag(boolean flag) { this.flag = flag; }} public static void main(String[] args) throws InterruptedException { MyRunnable myRunnable = new MyRunnable(); new Thread(myRunnable).start(); Thread.sleep(2000); //main线程修正变量 myRunnable.setFlag(false); }9. 线程池ThreadPool

线程的缓冲池,目的便是提高效率. new Thread().start() ,线程是内存中的一个独立的方法栈区,JVM没有能力开辟内存空间,和OS交互.

JDK5开始内置线程池

9.1 Executors类静态方法static newFixedThreadPool(int 线程的个数)方法的返回值ExecutorService接口的实现类,管理池子里面的线程

ExecutorService接口的方法submit (Runnable r)提交线程实行的任务

9.2 Callable接口

实现多线程的程序 : 接口特点是有返回值,可以抛出非常 (Runnable没有)

抽象的方法只有一个, call

启动线程,线程调用重写方法call

ExecutorService接口的方法submit (Callable c)提交线程实行的任务Future submit()方法提交线程任务后,方法有个返回值 Future接口类型Future接口,获取到线程实行后的返回值结果

public class MyCall implements Callable<String> { public String call() throws Exception{ return "返回字符串"; }} public static void main(String[] args) throws ExecutionException, InterruptedException { //创建线程池,线程的个数是2个 ExecutorService es = Executors.newFixedThreadPool(2); //线程池管理工具service,调用方法啊submit提交线程的任务 MyRunnable my = new MyRunnable(); //提交线程任务,利用Callable接口实现类 Future<String> future = es.submit(new MyCall());//返回接口类型 Future //接口的方法get,获取线程的返回值 String str = future.get(); System.out.println("str = " + str);// es.submit(my);// es.submit(my);// es.submit(my); // es.shutdown();//销毁线程池 }10. ConcurrentHashMap

ConcurrentHashMap类实质上Map凑集,键值对的凑集.利用办法和HashMap没有差异.

凡是对付此Map凑集的操作,不去修正里面的元素,不会锁定

11. 线程的状态图-生命周期

在某一个时候,线程只能处于个中的一种状态. 这种线程的状态反应的是JVM中的线程状态和OS无关.

文章来源:https://www.52pojie.cn/forum.php?mod=viewthread&tid=1552647&extra=page%3D2%26filter%3Dtypeid%26typeid%3D192#40832112_1.-线程的基本观点