多线程知识回顾
1、多线程基础知识
多线程之间抢占资源,会存在大量的保护现场(包括执行的变量数据等等资源)和恢复现场(恢复刚才执行到那一步了)。所以也会比较慢。
什么是NIO和BIO呢?Nginx就是NIO,当大量请求过来时,nginx会开启线程来接受请求,但Http请求是BIO,需求请求等待逐个执行了。
2、进程的概念:
进程是申请资源的最小单位,所有的线程共享进程的资源,一个进程最少会有一个线程,多的就是无数了。
3、多线程咋说:
如果电脑是一核一个CPU,那么同时只能执行一个进程的一个线程。现在是超线程技术。一个cpu执行两个线程。四核八线程。就是四个CPU可以执行八个线程。
4、多线程的创建:
5、创建线程的问题: 使用thread和runnable的区别。一个是创建一个对象,一个是创建多个对象。
/** * 此时出现的问题: * 1、每次在启动线程对象的时候都会创建自己对象的属性值,相当于每个线程操作自己,没有真正意义上实现贡献 * 解决方法:将共享对象,共享变量设置成static * 2、每次访问共享对象的时候,数据不一致了、 * 解决方法:使用线程同步 * * */ public class TicketThread extends Thread{ private static int ticket = 5; @Override public void run() { for(int i = 0;i<100;i++){ if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票"); } } } public static void main(String[] args) { TicketThread t1 = new TicketThread(); TicketThread t2 = new TicketThread(); TicketThread t3 = new TicketThread(); TicketThread t4 = new TicketThread(); t1.start(); t2.start(); t3.start(); t4.start(); } }
1 /** 2 * 使用接口的方式,每次只创建了一个共享对象,所有的线程能够实现资源共享 3 * 1、数据不一致的问题 4 * 解决方法:线程同步 5 * 6 */ 7 public class TicketRunnable implements Runnable { 8 9 private int ticket = 5; 10 11 @Override 12 public void run() { 13 for (int i = 0; i < 100; i++) { 14 if (ticket > 0) { 15 System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票"); 16 } 17 } 18 } 19 20 public static void main(String[] args) { 21 TicketRunnable ticket = new TicketRunnable(); 22 Thread t1 = new Thread(ticket); 23 Thread t2 = new Thread(ticket); 24 Thread t3 = new Thread(ticket); 25 Thread t4 = new Thread(ticket); 26 27 t1.start(); 28 t2.start(); 29 t3.start(); 30 t4.start(); 31 } 32 }
6、多线程之间的代理模式设计: 来自/设计模式之禅
第 2 章 代理模式【Proxy Pattern】 什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道 被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,代理人虽然不能干活,但是被 代理的人能干活呀。 比如西门庆找潘金莲,那潘金莲不好意思答复呀,咋办,找那个王婆做代理,表现在程序上时这样的: 先定义一种类型的女人: package com.cbf4life.proxy; /** * @author cbf4Life cbf4life@126.com * I'm glad to share my knowledge with you all. * 定义一种类型的女人,王婆和潘金莲都属于这个类型的女人 */ public interface KindWomen { //这种类型的女人能做什么事情呢? public void makeEyesWithMan(); //抛媚眼 public void happyWithMan(); //happy what? You know that! } 一种类型嘛,那肯定是接口,然后定义潘金莲: package com.cbf4life.proxy; /** * @author cbf4Life cbf4life@126.com * I'm glad to share my knowledge with you all. * 定一个潘金莲是什么样的人 */ public class PanJinLian implements KindWomen { public void happyWithMan() { System.out.println("潘金莲在和男人做那个....."); } 第 8 页 您的设计模式 public void makeEyesWithMan() { System.out.println("潘金莲抛媚眼"); } } 再定一个丑陋的王婆: package com.cbf4life.proxy; /** * @author cbf4Life cbf4life@126.com * I'm glad to share my knowledge with you all. * 王婆这个人老聪明了,她太老了,是个男人都看不上, * 但是她有智慧有经验呀,她作为一类女人的代理! */ public class WangPo implements KindWomen { private KindWomen kindWomen; public WangPo(){ //默认的话,是潘金莲的代理 this.kindWomen = new PanJinLian(); } //她可以是KindWomen的任何一个女人的代理,只要你是这一类型 public WangPo(KindWomen kindWomen){ this.kindWomen = kindWomen; } public void happyWithMan() { this.kindWomen.happyWithMan(); //自己老了,干不了,可以让年轻的代替 } public void makeEyesWithMan() { this.kindWomen.makeEyesWithMan(); //王婆这么大年龄了,谁看她抛媚眼?! } } 两个女主角都上场了,男主角也该出现了: 第 9 页 您的设计模式 package com.cbf4life.proxy; /** * @author cbf4Life cbf4life@126.com * I'm glad to share my knowledge with you all. * 定义一个西门庆,这人色中饿鬼 */ public class XiMenQing { /* * 水浒里是这样写的:西门庆被潘金莲用竹竿敲了一下难道,痴迷了, * 被王婆看到了, 就开始撮合两人好事,王婆作为潘金莲的代理人 * 收了不少好处费,那我们假设一下: * 如果没有王婆在中间牵线,这两个不要脸的能成吗?难说的很! */ public static void main(String[] args) { //把王婆叫出来 WangPo wangPo = new WangPo(); //然后西门庆就说,我要和潘金莲happy,然后王婆就安排了西门庆丢筷子的那出戏: wangPo.makeEyesWithMan(); //看到没,虽然表面上时王婆在做,实际上爽的是潘金莲 wangPo.happyWithMan(); } } 那这就是活生生的一个例子,通过代理人实现了某种目的,如果真去掉王婆这个中间环节,直接是西 门庆和潘金莲勾搭,估计很难成就武松杀嫂事件。 那我们再考虑一下,水浒里还有没有这类型的女人?有,卢俊义的老婆贾氏(就是和那个固管家苟合 的那个),这名字起的:“假使”,那我们也让王婆做她的代理: 把贾氏素描出来: package com.cbf4life.proxy; /** * @author cbf4Life cbf4life@126.com * I'm glad to share my knowledge with you all. */ public class JiaShi implements KindWomen { public void happyWithMan() { System.out.println("贾氏正在Happy中......"); 第 10 页 您的设计模式 } public void makeEyesWithMan() { System.out.println("贾氏抛媚眼"); } } 西门庆勾贾氏: package com.cbf4life.proxy; /** * @author cbf4Life cbf4life@126.com * I'm glad to share my knowledge with you all. * 定义一个西门庆,这人色中饿鬼 */ public class XiMenQing { public static void main(String[] args) { //改编一下历史,贾氏被西门庆勾走: JiaShi jiaShi = new JiaShi(); WangPo wangPo = new WangPo(jiaShi); //让王婆作为贾氏的代理人 wangPo.makeEyesWithMan(); wangPo.happyWithMan(); } } 说完这个故事,那额总结一下,代理模式主要使用了 Java 的多态,干活的是被代理类,代理类主要是 接活,你让我干活,好,我交给幕后的类去干,你满意就成,那怎么知道被代理类能不能干呢?同根就成, 大家知根知底,你能做啥,我能做啥都清楚的很,同一个接口呗。
7、线程的状态: 进入线程阻塞状态有两种情况: 1、sleep 2、io阻塞。3、join方法。会阻塞当前的运行的线程,让别的线程运行。
进入死亡情况有三种情况:1、正常执行完成 2、人为中断,使用stop方法 3、程序抛出未捕获的异常
8、线程常见api
join方法:让出当前运行的线程,让别的线程执行。调用该方法的线程强制执行。阻塞状态
sleep():静态方法,让当前运行的线程睡眠多少毫秒,让别的线程来执行。阻塞状态
yield()当前正在执行的线程暂停一次,允许其他线程执 行,不阻塞,线程进入就绪状态。可以再次进行资源的同时抢占 就绪状态
stop() 强迫线程停止执行。已过时。不推荐使用。
9、线程安全数据同步问题:
就是加锁
还有轻量级的CAS compare and swit
synchronized 同步代码块,参数为当前对象。也就是当前的Thread对象。睡眠可以切换不同对象的资源抢占。
注意:
* 在多线程的时候,可以实现唤醒和等待的过程,但是唤醒和等待操作的对应不是thread类
* 而是我们设置的共享对象或者共享变量
* 多线程并发访问的时候回出现数据安全问题:
* 解决方式:
* 1、同步代码块
* synchronized(共享资源、共享对象,需要是object的子类){具体执行的代码块}
* 2、同步方法
* 将核心的代码逻辑定义成一个方法,使用synchronized关键字进行修饰,此时不需要指定共享对象
*
public class TicketRunnable2 implements Runnable { private int ticket = 5; @Override public void run() { for (int i = 0; i < 100; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (this){ if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票"); } } } } public static void main(String[] args) { TicketRunnable2 ticket = new TicketRunnable2(); Thread t1 = new Thread(ticket,"A"); Thread t2 = new Thread(ticket,"B"); Thread t3 = new Thread(ticket,"C"); Thread t4 = new Thread(ticket,"D"); t1.start(); t2.start(); t3.start(); t4.start(); } }
10、同步方法的实现
11、生产和消费者的问题
可以用wait和notify 现在用的是 java.util.concurrent 下的阻塞队列。
12、线程池创建任务的过程:第三点是所有的线程,并非第一点的核心线程数。
13、线程池的分类:
第二个是延迟执行线程池。
1 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3); 2 System.out.println(System.currentTimeMillis()); 3 scheduledExecutorService.schedule(new Runnable() { 4 @Override 5 public void run() { 6 System.out.println("延迟三秒执行"); 7 System.out.println(System.currentTimeMillis()); 8 } 9 },3, TimeUnit.SECONDS); 10 scheduledExecutorService.shutdown();
延迟执行,每三秒执行一次
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); System.out.println(System.currentTimeMillis()); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("1------延迟一秒执行,每三秒执行一次"); System.out.println(System.currentTimeMillis()); } },1,3, TimeUnit.SECONDS);
创建带有返回结果的线程两种方式:
FutureTask
1 @SuppressWarnings("all") 2 public static void main(String[] args) throws ExecutionException, InterruptedException { 3 FutureTask futureTask = new FutureTask(new MyCallable()); 4 Thread thread = new Thread(futureTask); 5 thread.start(); 6 if(!futureTask.isDone()) 7 System.out.println("task has not finished!"); 8 System.out.println(futureTask.get()); 9 }
线程池
1 @SuppressWarnings("all") 2 public static void main(String[] args) throws ExecutionException, InterruptedException { 3 ExecutorService executorService = Executors.newCachedThreadPool(); 4 Future future = executorService.submit(new MyCallable()); 5 if(!future.isDone()) 6 System.out.println("task has not finished!"); 7 System.out.println(future.get()); 8 }
本文来自博客园,作者:Jerry&Ming,转载请注明原文链接:https://www.cnblogs.com/jerry-ming/articles/16099265.html