2.1并行和并发
并行就是多个cpu执行多个,并发就是一个cpu执行多个
使用多线程的优点
1提高了程序的响应速度,对图形优化更加有意义嘛让用户体验更好
2.提高cpu的使用效率
2.2创建线程的方式在jdk1.5版本之前是两种分别是Thread类和Runnable接口,在JDK1.5以后新增了线程池所以是三种
第一种是继承Thread类
步骤是四步
-
定义子类继承Thread类。
-
子类中重写Thread类中的run方法。
-
创建Thread子类对象,即创建了线程对象。
-
调用线程对象start方法:启动线程,调用run方法。
第二种是实现 Runnable 接口
步骤是五步
1.定义子类,实现Runnable接口。 2.子类中重写Runnable接口中的run方法。 3.通过Thread类含参构造器创建线程对象。 4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。 5.调用Thread类的start方法:开启线程, 调用Runnable子类接口的run方法。
第三种是线程池的方式,通过Callable 和 Future 创建线程
-
-
创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
-
-
-
创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
-
-
-
使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
-
-
-
调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
-
2.3Thread类和Runnable 接口区别
因为Thread类线程代码存放Thread子类run方法中。Runnable 接口线程代码存在接口的子类的run方法所以如果一个类是继承Thread类,来使用多线程的那么他则不适合资源共享,但是如果实现了Runable接口的话,则很容易的实现资源共享。
线程是话是有一个生命周期的
分为五种状态
1.新建,一个线程被生命创建属于就绪状态
2.就绪,新建状态的线程被start()后,将进入线程队列等待CPU时间片
3.运行,run()方法定义了线程的操作和功能
4.阻塞,在一些特殊情况下,让CPU中止自己的执行状态进入阻塞
5.死亡,执行完成或者提前中止
同步最最安全,最保险的。而异步不安全,容易导致死锁,这样一个线程死掉就会导致整个进程崩溃,但没有同步机制的存在,性能会有所提升
说到同步就要提到锁Synchronized,锁是可以保证线程的同步数据的安全,但是性能会相对降低一些,加锁也会出现死锁问题不同的线程分别占用对方所需要的同步资源不放弃,都在等待对方放弃自己的所需要的同步资源,就形成死锁,死锁以后不会出现异常,没有什么提示但是所以线程会进入阻塞状态
解决方法的话
1.可以用专门的线程算法,指定规则
2.经量去减少一些同步资源的定义
3.避免嵌套使用锁
Lock锁是JDK1.5以后提供的一个性能更强大的锁他跟Synchronized的区别
1.Lock是显式锁但是他是需要手动开启和关闭的,Synchronized是隐式锁自动释放开启
2.Lock只有同步代码块,但是Synchronized有代码块和方法锁
3.使用Lock锁, JVM将花费较少的时间来调度线程,性能更好
2.4线程池创建线程
1.Java 创建线程池主要有两种方法,一种是通过 Executors 工厂类提供的方法,该类提供了4种不同的线程池;另一种是通过 ThreadPoolExecutor类进行自定义创建。
Executors 工厂类提供的方法如下
1.newCachedThreadPool
创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程。
2.newFixedThreadPool
创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待。
3.newScheduledThreadPool
创建一个周期性的线程池,支持定时及周期性执行任务。
4.newSingleThreadExecutor
创建一个单线程的线程池,可保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
2.通过ThreadPoolExecutor类自定义
7个参数如下:
(1)corePoolSize:核心线程数,线程池中始终存活的线程数。
(2)maximumPoolSize: 最大线程数,线程池中允许的最大线程数。
(3)keepAliveTime: 存活时间,线程没有任务执行时最多保持多久时间会终止。
(4)unit: 单位,参数 keepAliveTime 的时间单位,7种可选。
(5)workQueue: 一个阻塞队列,用来存储等待执行的任务,均为线程安全,7种可选。
(6)threadFactory: 线程工厂,主要用来创建线程,默及正常优先级、非守护线程。
(7)handler:拒绝策略,拒绝处理任务时的策略,4种可选,默认为 AbortPolicy。
这两种方式我更推荐使用第二个通过ThreadPoolExecutor类自定义线程池
这样的处理方式让写的开发人员更加明确线程池的运行规则,规避资源耗尽的风险。 Executors返回的线程池对象的弊端如下: FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。 CachedThreadPool和ScheduledThreadPool:允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。
OOM为out of memory的简称,称之为内存溢出