多线程的三种实现
来源:互联网 发布:maven java 7 home 编辑:程序博客网 时间:2024/05/13 14:24
最近写多篇关于多线程的博客,这里做个总结。线程从创建到消亡的过程中,可能会经历五种状态:
- New:线程刚被创建。
- Runnable:线程的start方法被调用后所处的状态,该状态下,线程才有了竞争时间片的可能,即可运行态。
- Running:线程正在执行run方法
- Dead:执行完run方法,或者被stop
- Blocked:线程放弃CPU使用权,进入阻塞状态。该状态下,线程可能重新被赋予CPU使用权进入Runnable状态,也可能直接消亡。阻塞状态可以细分成三种:
- 等待阻塞:Runnable状态的的中运行Object的wait方法,被JVM放入等待池。
- 同步阻塞:线程竞争同步锁失败,被JVM放入锁池。
- 其他:线程执行sleep、Join等方法,被JVM置为阻塞状态,等待JVM重置状态为Runnable。
Java中实现多线程的方式主要有三种:继承Thread类、实现Runnable接口与使用线程池。
继承Thread类与实现Runnable接口
需要重写Thread类的run方法,或者实现Runnable的run方法,通过调用线程的start方法,启动线程。直接上例子:
package test.thread;import java.util.LinkedList;import java.util.Queue;public class ThreadTest1 {public static void main(String[] args) {final Queue<Integer> queue = new LinkedList<Integer>();for (int i = 0; i < 1000; i++) {queue.add(i);}Thread[] threads = new Thread[10];for (int i = 0; i < 10; i++) {threads[i] = new Thread(new Runnable() {@Overridepublic void run() {synchronized (queue) {try {queue.wait();} catch (InterruptedException e) {e.printStackTrace();}for (int j = 0; j < 100; j++) {System.out.println(Thread.currentThread().getName() + ": " + queue.poll());}}}});threads[i].start();}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (queue) {queue.notifyAll();}}}上面例子,在主线程与10个子线程中都用到了共享变量queue。通过调用queue的wait方法阻塞子线程,等待主线程调用notifyAll方法时,重新进入Runnable状态,保证了线程安全。需要注意object的wait、notify、notifyAll等方法需要放在同步块中。
同样的功能,我们也可以这样实现:
package test.thread;import java.util.LinkedList;import java.util.Queue;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ThreadTest2 {public static void main(String[] args) {final Lock lock = new ReentrantLock();final Condition condition = lock.newCondition();final Queue<Integer> queue = new LinkedList<Integer>();for (int i = 0; i < 1000; i++) {queue.add(i);}Thread[] threads = new Thread[10];for (int i = 0; i < 10; i++) {threads[i] = new Thread(new Runnable() {@Overridepublic void run() {lock.lock();try {condition.await();for (int j = 0; j < 100; j++) {System.out.println(Thread.currentThread().getName() + ": " + queue.poll());}} catch (InterruptedException e1) {e1.printStackTrace();} finally {lock.unlock();}}});threads[i].start();}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}lock.lock();try {condition.signalAll();} finally {lock.unlock();}}}上面例子用到了ReentrantLock,相比synchronized关键字提供更加精细的同步锁功能。使用时需要注意要把锁的unlock方法,置于finally块中,避免线程异常中断,锁不被释放。
我们还可以这样实现:
package test.thread;import java.util.LinkedList;import java.util.Queue;import java.util.concurrent.Semaphore;public class ThreadTest3 {public static void main(String[] args) {final Semaphore semaphore = new Semaphore(1);final Queue<Integer> queue = new LinkedList<Integer>();for (int i = 0; i < 1000; i++) {queue.add(i);}Thread[] threads = new Thread[10];for (int i = 0; i < 10; i++) {threads[i] = new Thread(new Runnable() {@Overridepublic void run() {try {semaphore.acquire(1);for (int j = 0; j < 100; j++) {System.out.println(Thread.currentThread().getName() + ": " + queue.poll());}} catch (Exception e1) {e1.printStackTrace();} finally {semaphore.release(1);}}});threads[i].start();}}}
这个例子中,我们用到了信号量。当线程获得semaphore时,如果semaphore的内部计数值大于0,就会减少计数值并允许访问共享资源。
使用线程池
实现线程池主要通过Executors工具类以及ThreadPoolExecutor线程池实现类。ThreadPoolExecutor是线程池的核心功能,这里先挖个坑,后面有时间再整理。Executors提供了四种线程池:
newCachedThreadPool
该方法创建一个可缓存的线程。线程池无线大,可以复用已经执行完璧的线程。
newScheduledThreadPool
该方法创建一个定长的线程。可以实现并发线程个数,超过并发线程个数的线程进入等待队列。
newScheduledThreadPool
该方法创建一个定长的线程,支持周期性任务的执行。
newSingleThreadExecutor
该方法创建一个单线程化的线程池,同一时间只有一个线程在执行任务。
0 0
- 多线程的三种实现
- 多线程的三种实现
- 三种iOS多线程实现的方法
- JAVA多线程实现的三种方式
- Java多线程实现的三种方式
- JAVA多线程实现的三种方式
- JAVA多线程实现的三种方式
- JAVA多线程实现的三种方式
- JAVA多线程实现的三种方式
- Java多线程的三种实现方式
- JAVA多线程实现的三种方式
- JAVA多线程实现的三种方式
- JAVA多线程实现的三种方式
- java多线程实现的三种方式
- JAVA多线程实现的三种方式
- java实现多线程的三种方式
- JAVA多线程实现的三种方式
- Java实现多线程的三种方式
- Java中的命令模式
- 2.统计输入的行数,单词数和字符数
- 剑指Offer_2题
- Express和koa各有啥优缺点?
- C语言高精度加法
- 多线程的三种实现
- Android的权限设置及自启动设置
- JAVA线程详细解释
- ELK学习系列文章第二章:elasticsearch常见错误与配置简介
- Angular2笔记(1)——初步认识
- 鸡兔同笼
- 进程、线程、协程之概念理解
- 程序员基础知识(大牛点评)
- cookie和session的区别和用法