多线程的三种实现

    最近写多篇关于多线程的博客,这里做个总结。线程从创建到消亡的过程中,可能会经历五种状态:

  1. New:线程刚被创建。
  2. Runnable:线程的start方法被调用后所处的状态,该状态下,线程才有了竞争时间片的可能,即可运行态。
  3. Running:线程正在执行run方法
  4. Dead:执行完run方法,或者被stop
  5. 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() {

				@Override
				public 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() {

				@Override
				public 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() {

				@Override
				public 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

    该方法创建一个可缓存的线程。线程池无线大,可以复用已经执行完成的线程。

newFixedThreadPool

    该方法创建一个定长的线程。可以实现并发线程个数,超过并发线程个数的线程进入等待队列。

newScheduledThreadPool

    该方法创建一个定长的线程,支持周期性任务的执行。

newSingleThreadExecutor

    该方法创建一个单线程化的线程池,同一时间只有一个线程在执行任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值