查关键词热度的网站,戴尔公司网站建设成功的关键是什么,网络规划设计师教程读后感,石狮做网站撸一撸多线程的来龙去脉你就知道#xff0c;为什么面试官折磨喜欢问这种问题了#xff01;
有一天张三去面试#xff0c;被面试官问了一个问题:
什么叫多线程#xff1f; 张三#xff1a;多线程就是多个线程在cpu上执行#xff0c;抢占Cpu资源#xff0c;提高CPU执…撸一撸多线程的来龙去脉你就知道为什么面试官折磨喜欢问这种问题了
有一天张三去面试被面试官问了一个问题:
什么叫多线程 张三多线程就是多个线程在cpu上执行抢占Cpu资源提高CPU执行效率… 面试官你在说什么你懂什么?你到底学了什么回去吧你!!! 张三很伤心出来的时候在路上直接一把抢了大妈的**《java从入门到放弃》**一回去就把java多线程复习了一遍。
一、认识多线程
1.多任务
2.多线程
3.程序、进程、线程
程序指令和数据的有序集合其本身没有任何运行含义是一个静态概念。进程是程序的一次执行过程是动态概念。是系统分配的基本单位。线程一个进程通常包含若干个线程是cpu调度和执行的基本单位。
多线程multithreading是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中这些独立运行的程序片段叫作“线程”Thread利用它编程的概念就叫作“多线程处理”。
二、创建线程
1.继承Thread类 自定义线程类继承Thread类 重写run()方法编写线程执行体 创建线程对象调用star()方法启动线程 public class MyThread extends Thread{private int key 100;public synchronized int getKey(){return key;}public synchronized void setKey(){this.key - 1;}Overridepublic void run(){while(getKey()0){System.out.println(MyThread);setKey();}}//主线程public static void main(String []args){MyThread myThread new Mythread();//创建线程myThread.start();//启动线程while(myThread.getKey()0){System.out.println(主线程);myThread.setKey();}}
}2.实现Runnable接口 定义Runnable接口实现类 实现run()方法编写线程执行体 创建线程对象调用start()方法启动线程 解决了单继承的局限性 public class MyRunnable implements Runnable{private int key 100;public synchronized int getKey(){return key;}public synchronized void setKey(){this.key - 1;}Overridepublic void run(){while(getKey()0){System.out.println(MyThread);setKey();}}//主线程public static void main(String []args){MyRunnable myRunnable new MyRunnable();Thread myThread new Thread(myRunnable);//创建线程myThread.start();//启动线程while(myRunnable.getKey()0){System.out.println(主线程);myRunnable.setKey();}}
}3.实现Callable接口
public class MyCallable implements CallableBoolean{Overridepublic Boolean call(){return true;}public static void main(String[]args){MyCallable c1 new MyCallable();MyCallable c2 new MyCallable();ExecutorService service Executors.newFixedThreadPool(2);FutureBoolean result1 service.submit(c1);FutureBoolean result2 service.submit(c1);Boolean b1 result1.get();Boolean b2 result2.get();service.shutdownNow();}
}实现Callable接口需要返回值类型 重写call方法需要抛出异常 创建目标方法 创建执行服务ExecutorSevice service Executors.newFixedThreadPool(1);//创建1个服务 提交执行Future Boolean result service.submit(thread);//添加服务thread 获取结果Boolean b result.get(); 关闭服务 service.shutdownNow();
三、线程状态 1.线程停止
stop()方法//不建议使用已被jdk弃用
2.线程休眠
sleep(int time);存在InterruptedException异常休眠时间完成后线程进入就绪状态等待CPU调度调用sleep()方法的线程不会释放锁锁依然被调用者占用
3.线程暂停
yield();线程进入就绪状态不阻塞线程重新进入CPU就绪队列等待CPU调度调用者会释放锁。
4.合并线程
join();插入线程后其他线程进入阻塞队列待插入线程执行完成后释放CPU资源后再进入就绪队列等待处理机调度。
5.线程状态
Thread.State:
NEW:线程创建成功但未启动RUNNABLE线程正处于JVM中执行BLOCK线程阻塞等待监视器锁定WAITING等待CPU释放资源此时资源被其他线程占用TIMED_WAITING等待其他线程执行特定动作达到特定时间的线程TERMINATED线程执行已完成线程死亡。此时线程失去star()机会。
6.线程优先级
Thread.Priority:
MIN_PRIORITY 1;//最小优先级MAX_PRIORITY 10;//最大优先级NORM_PRIORITY 5;//默认优先级
优先级高低意味着获得CPU调度的概率高低高优先级线程等待低优先级线程释放资源会造成性能倒置问题
设置优先级setPriority(int num);
获取优先级getPriority();
7.守护线程
Thread.daemon: 用户线程 守护线程 JVM会确保用户线程执行完毕JVM不需要等待守护线程的执行完成守护线程一般有操作日志、监控内存、GC垃圾回收等。
四、线程同步
多个线程操作同一资源
1.并发和并行
并发一个时间段的线程代码运行时其它线程处于挂起状;并行当一个CPU执行一个线程时另一个CPU可以执行另一个线程两个线程互不抢占CPU资源可以同时进行.
2.队列和锁
当一个线程获得对象排它锁独占资源时如果此时其他线程需要获得此对象则必须等待该线程释放这个锁才能拥有获得此锁的机会。
一个线程持有锁会导致其他竞争此锁的进程挂起多线程场景下加锁与释放锁会导致进程上下文切换以及CPU调度延时引起性能问题同样性能倒置问题的发生会引起性能问题。
3.同步方法
synchronized同步方法控制资源的访问即每个资源都使用了一把锁每个synchronized方法必须获得使用该资源的锁才能访问否则需要访问此资源的线程进入阻塞队列等待资源的释放同步方法一旦执行执行线程则独占该锁直到执行结束后才释放此锁。
public synchronized void fun(){/**执行代码块*/
}4.同步块
public void fun(Object obj){synchronized(obj){/**执行代码块*/}
}obj同步监视器可以是任意对象一般使用共享资源作为同步监视器。同步方法中无需指定同步监视器同步方法中的监视器为this是对象本身同步监视器执行流程 线程1访问共享资源锁定同步监视器开始执行同步代码块此时线程2也要访问该同步资源发现同步监视器已经被锁定则访问不能进行开始等待同步监视器被释放当线程1执行完成同步代码块线程1立即释放同步监视器资源解锁线程2对共享资源进行访问同时锁定同步监视器后进入同步代码块线程2对同步资源的访问完成释放同步监视器接触对共享资源的占用。
5.死锁
多个线程各自占用共享资源并相互等待其他线程占有的资源才能运行死锁导致两个或多个线程都在等待对方释放资源产生死锁的四个必要条件 互斥条件一个资源每次只允许一个进程使用请求与保持一个进程因请求与保持时已获得的资源保持不变不可剥夺条件进程未使用完获得的资源时不能强行剥夺循环等待条件若干资源之间形成一种头尾相接的循环等待资源关系。
6.Lock锁 加锁与释放锁 ReentrantLock lock new ReentrantLock();
public void fun(){lock.lock();//显式加锁/**同步代码块*/lock.unlock();//显式解锁
}Lock锁通过显式定义锁对象实现同步 Lock锁提供了对共享资源的独占访问即每次只有一个线程对Lock锁对象加锁线程访问共享资源前需要获得锁对象 ReentrantLock实现了Lock接口拥有与synchronized相同的并发性和内存语义在实现线程安全的控制中被常用 synchronized与Lock的对比 Lock是显示锁手动开关锁而synchronized是隐式锁离开作用域锁自动释放Lock只有代码块锁而synchronized拥有方法锁和代码块锁使用Lock锁JVM调度线程时花费的时间较少锁的优先使用顺序Lock 同步代码块 同步方法。
五、线程通信
1.线程通信的方法
wait();//线程等待notify();//通知notifyAll();//通知全部其他线程
2.生产者消费者模式 1管程法
//产品类
public class Product{String name;public Product() {}public Product(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}
}//消费者
public class User implements Runnable{Factory factory;User(){}User(Factory factory){this.factory factory;}Overridepublic void run() {for (int i 0; i 20; i) factory.getProduct();}
}//生产者
public class Productor implements Runnable{Factory factory;Productor(){}Productor(Factory factory){this.factory factory;}Overridepublic void run() {for (int i 0; i 20; i)factory.setProduct(new Product(产品:(i1)));}
}
//工厂类
public class Factory{final int PRODUCT_MAX_NUM 10;//产品集合Product [] products new Product[PRODUCT_MAX_NUM];//产品计数器int proCount0;//生产产品public synchronized void setProduct(Product item){if(proCount PRODUCT_MAX_NUM-1){System.out.println(产品达到了库存停止生产...);try {wait();} catch (InterruptedException e) {e.printStackTrace();}}products[proCount] item;proCount;System.out.println(生产者生产了产品:item.getName()通知消费者消费...);notifyAll();}//消费产品public synchronized Product getProduct(){if (proCount 0){System.out.println(没有产品可以消费了...);try {wait();} catch (InterruptedException e) {e.printStackTrace();}}Product item products[proCount-1];System.out.println(消费者消费了产品:item.getName());notifyAll();proCount--;return item;}public static void main(String[] args) {Factory factory new Factory();new Thread(new Productor(factory)).start();new Thread(new User(factory)).start();}
}2信号灯法
//工厂类
public class Factory{final int PRODUCT_MAX_NUM 10;//产品集合Product [] products new Product[PRODUCT_MAX_NUM];//产品计数器int proCount0;//信号量boolean single false;//生产产品public synchronized void setProduct(Product item){if(proCount PRODUCT_MAX_NUM){single true;System.out.println(产品达到了库存停止生产...);try {wait();} catch (InterruptedException e) {e.printStackTrace();}}products[proCount] item;single true;proCount;System.out.println(生产者生产了产品:item.getName()通知消费者消费...);notifyAll();}//消费产品public synchronized Product getProduct(){if (!single){System.out.println(没有产品可以消费了...);try {wait();} catch (InterruptedException e) {e.printStackTrace();}}Product item products[proCount-1];System.out.println(消费者消费了产品:item.getName());notifyAll();single --proCount ! 0;return item;}public static void main(String[] args) {Factory factory new Factory();new Thread(new Productor(factory)).start();new Thread(new User(factory)).start();}
}3.线程池
//1-使用ThreadPoolExecutor()构造方法直接创建线程池实例
ExecutorService es new ThreadPoolExecutor(10,//corePoolSize线程核心池大小110,//maximunPoolSize最大线程数1010L,//keepAliveTime线程没有任务后保持10毫秒后停止TimeUnit.MICROSECONDS,//以ms为单位new LinkedBlockingQueueRunnable()
);//2-创建一个固定容量为10的线程池
ExecutorService es1 Executors.newFixedThreadPool(10);
/*源码
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueueRunnable());}
*///3-创建一个可缓存的线程池不对线程池大小做现在
// 线程池大小取决于OS或者说JVM能够创建的最大线程数
// 线程没有任务后保持60秒后停止
ExecutorService es2 Executors.newCachedThreadPool();
/*源码
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueueRunnable());
}
*/
//4-创建一个单线程化的线程池使用唯一的工作线程来执行任务
ExecutorService es3 Executors.newSingleThreadExecutor();
/*源码
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueueRunnable()));
}
*///创建一个固定大小的线程池支持定时周期任务
ExecutorService es4 Executors.newScheduledThreadPool(10);
/*源码
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);
}
*/ 优点 提高响应速度降低资源消耗便于线程的管理 内容 ExecutorService和ExecutorscorePoolSize:线程核心池大小maximunPoolSize:最大线程数keepAliveTime:线程没有任务后保持多久后停止 ThreadPoolExecutor是ExecutorService的子类 void executor(Runnable able):无返回值执行任务传递参数为Runnable ExecutorService es Executors.newFixedThreadPool(10);//创建一个容量为10的线程池es.submit(new Runnable() {Overridepublic void run() {System.out.println(Runnable接口);}});
//es.submit(()- System.out.println(Runnable接口));//使用lamda表达式简写
es.shutdown();//关闭线程池T Future T submit(Callable T able):带返回值执行任务传递参数为Callable; ExecutorService es Executors.newFixedThreadPool(10);FutureTaskString ft new FutureTaskString(new CallableString() {Overridepublic String call() throws Exception {return Callable接口;}});es.submit(ft);try {System.out.println(ft.get());//获取执行结果} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}es.shutdown();//关闭线程池Executors:工具类线程池工厂类用于创建并返回不同类型线程池
总结
好了关于多线程也就到此告一段落吧
java这条路通往何方张三又该何去何从
一切都没有定数
我们只知道他拿走了那本书
拿走的不是简简单单几张纸
拿走的是他的青春和无穷无尽地“快乐”
张三也许会说不就是java多线程吗我分分钟肝到底但是他永远不会知道等待他的后果绝对不是他想要的结果而那个阿姨她将用她的一生来治愈她失去的《java从入门到放弃》是的张三他输了他不是输给了面试官也不是输给了多线程他失败得彻彻底底他失败得一塌糊地