(下面的描述和代码摘抄自书目《java编程思想》)
基本的线程机制:
并发编程使我们可以将程序划分为多个分离的,独立运行的任务。通过使用多线程机制,这些独立任务(也被称为子任务)中的每一个都将有执行线程来驱动。一个线程就是在进程中的一个单一的顺序控制流,因此,单个线程可以拥有多个并发执行的任务,但是程序使得每个任务都好像有自己 的CPU一样。
一、创建多线程基本的2种方法:
2种方法首先先要实现Runnable接口并编写run()方法:
public class LiftOff implements Runnable {
protected int countDown =10;
private static int taskCount=0;
private final int id = taskCount++;
public LiftOff(){}
public LiftOff(int countDown){
this.countDown= countDown;
}
public String status(){
return "#"+id+"("+(countDown>0?countDown:"LiftOff!")+"),";
}
public void run(){
while(countDown-->0){
System.out.print(status());
Thread.yield();
}
}
}
注:run()中对静态方法Thread.yield()的调用是对线程调度器的建议,他在声明:‘我已经执行完生命周期中最重要部分了,此刻可以切换给其他线程执行一段时间’;但是没有任何机制保证它会被采纳,当调用yield()也是在建议具有相同优先级的其他线程可以运行。
1.将Runnable对象提交给Thread构造器,并通过Thread对象的start()方法来启动线程。具体的看下面实现过程
/**
* 通过循环启动5个线程*/
public class BasicThreads {
public static void main(String[] args){
for(int i=0;i<5;i++){
Thread t = new Thread(new LiftOff());
t.start();
}
System.out.println("Waiting for LiftOff");
}
}
2.使用Executor
Java SE5的java.util.concurrent包中的执行器()管理Thread对象,从而简化并发编程:
public class ThreadsPool {
public static void main(String[] args){
//为每个任务创建一个线程
ExecutorService exec = Executors.newCachedThreadPool();
// //使用有限的线程集执行任务,预先确定FixedThreadPool使用的Thread的数量
// ExecutorService exec = Executors.newFixedThreadPool(5);
// //线程数量为1的FixedThreadPool,提交多个任务是,任务将会排队执行
// ExecutorService exec = Executors.newSingleThreadExecutor();
for(int i=0;i<5;i++){
exec.execute(new LiftOff());
}
exec.shutdown();
}
}
二、可以从任务中得到返回值的多线程
Runnable是执行工作的独立任务,但是它不返回任何值。如果希望在任务完成是能够返回一个值,可以实现Callable接口,Callable在Java SE5中引入,是一种具有类型参数的泛型,它的类型参数表示的是从call()(而不是run())中返回的值,并且必须使用ExecutorService.submit()方法调用它,下面是例子:
public class TaskWithResult implements Callable<String> {
private int id;
public TaskWithResult(int id){
this.id=id;
}
public String call(){
return "result of TaskWithResult "+id;
}
}
public class CallableDemo {
public static void main(String[] args){
List<Future<String>> results = new ArrayList<Future<String>>();
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
results.add(exec.submit(new TaskWithResult(i)));
}
for (Future<String> fs :results) {
try {
//可以用isDone()方法查询Future是否已经完成,否则get()将阻塞,直至结果准备就绪
System.out.println(fs.get());
} catch (InterruptedException e) {
e.printStackTrace();
return;
} catch (ExecutionException e) {
e.printStackTrace();
return;
}finally{
exec.shutdown();
}
}
}
}
submit()方法会产生Future对象,它用Callable返回结果的特定类型进行了参数化。可以用isDone()方法查询Future是否已经完成。也可以不用isDone()进行检查就直接调用get(),在这种情况下,get()将阻塞,直至结果准备就绪。
三、线程休眠
对线程进行休眠的一种简单方法是直接调用sleep(),将使任务中止执行给定的时间。下面的代码中的LiftOff类在本文第一段代码中。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**使用休眠的线程*/
public class SleepingTask extends LiftOff {
public void run(){
while(countDown-->0){
try {
System.out.print(status());
//Old-style:
//Thread.sleep(100);
//Java SE5/6-style:
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
public static void main(String[] args){
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
exec.execute(new SleepingTask());
}
exec.shutdown();
}
}
四、线程优先级
线程的优先级将改线程的重要性传递给了调度器,尽管CPU处理现有线程集的顺序是不确定的,但是调度器将倾向于让优先权最高的线程先执行。但是,并不是意味着优先权较低的线程将得不到执行(也就是说,优先级不会导致死锁),优先级较低的线程仅仅是执行的频率较低。
可以用getPriority()来读取现有线程的优先级,并且任何时刻都可以通过setPriority()来修改它
/**多线程优先级:优先级是在run()的开头部分设定的,在构造器中设定不会有任何好处,因为Excutor在此刻还没有执行任务
* */
public class SimplePriorities implements Runnable{
private int countDown=5;
private volatile double d;
private int priority;
public SimplePriorities(int priority){
this.priority = priority;
}
public String toString(){
return Thread.currentThread() +": "+countDown;
}
public void run(){
Thread.currentThread().setPriority(priority);//设置当前线程的优先级
while(true){
//An expensive interruptable operation
for(int i=0;i<100000;i++){
d += (Math.PI+Math.E)/(double)i;
if(i%1000==0) Thread.yield();
}
System.out.println(this);
if(--countDown==0) return;
}
}
public static void main(String[] args){
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
exec.execute(new SimplePriorities(Thread.MIN_PRIORITY));
}
exec.execute(new SimplePriorities(Thread.MAX_PRIORITY));
exec.shutdown();
}
}
注:优先级是在run()的开头部分设定的,在构造器中设置不会有任何好处,因为Executor在此刻还没有开始执行任务