实现多线程的三种方法
1.继承Thread类,重写run()方法
优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
缺点:因为该类已经继承了Thread类,所以不能在继承其他类;
2.实现runnable接口,重写run()方法
优点:线程只是实现了runnable接口,所以还可以继承其他类。在这种方式下多个线程可以共享同一个目标对象,所以非常适合多个线程共享同一份资源的情况;
缺点:稍微有一点复杂,如果需要访问当前线程,需要使用Thread.currentThread()方法
3.Callable接口通过FutureTask包装器来创建Thread线程,重写call();
拓展:runnable和Callable的区别参见:https://www.iteye.com/blog/uule-1488270
线程的生命周期
创建线程对象---start()就绪状态---sleep wait阻塞状态---运行状态run---终止状态stop;
线程池
线程池:java中开辟出了一种管理线程的概念,这个概念叫做线程池。从概念以及应用场景中我们可以看出,线程池的好处,就是可以方便的管理线程,也可以减少内存的消耗;
线程池的优势:
1.减少系统资源的消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;
2.提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行;
3.方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成CPU过度切换;
4.提供更强大的功能,延时定时线程池;
四种常见的线程池:
newCachedThreadPool:可缓存的线程池,该线程池中没有核心线程,不需要时就回收线程,适用于耗时少,任务量大的情况。
newSecudleThreadPool:周期性执行任务的线程池,按照某种特定的计划执行线程中任务,有核心线程,适用于执行周期性的任务。
newSingleThreadPool:只有一条线程来执行任务,适用于顺序的任务的应用场景。
newFixedThreadPool:定长的线程池,有核心线程,核心线程数即为最大的线程数量,没有非核心线程。
线程安全
使用多线程同步(synchronized)或加锁(lock)
多线程同步:当多个线程共享同一个资源时,不会受到其他线程的干扰。
解决线程安全:当把可能发生冲突的代码包裹在synchronized或者lock里面后,同一时刻只会有一个线程执行该段代码,其他线程必须等该线程执行完毕释放锁以后,才能去抢锁,抢到锁之后,才拥有执行权,这样就解决了数据的冲突,实现了线程安全。