JAVA完全参考手册(第8版) 第11章 多线程编程

1、基于进程的多任务处理“大局”,基于线程的多任务处理“细节”。多任务线程开销比多任务进程开销小,进程是重量级的任务,他们需要自己的地址空间,进程间通信开销很大且有很多限制;线程是轻量级任务,共享相同的地址空间,共享同一个重量级进程。基于多进程多任务不是由java控制的,多线程是由java控制的。

单线程系统使用轮询事件查询方法。在单核系统中,两个或者多个线程不是真正同时运行的,但是空闲时间被利用了,在多核系统中才有可能是真正同步执行的。Fork/Join框架。

线程优先级是一些整数,用于决定何时从一个运行的线程切换到下一个,即上下文切换,决定切换时机的规则比较简单:线程自愿放弃控制;线程被优先级更高的线程替换。如果优先级相同,对windows系统,以循环方式自动获得CPU资源,对于其他系统必须自愿地向其他线程放弃控制权(最安全的方法),否则其他线程就不能运行,所以会有可移植性问题。设置线程优先级setPriority()方法(final void setPriority(int level) 其中,level值必须在MIN_PRIORITY和MAX_PRIORITY之间,分别为1和10。默认优先级是NORM_PRIORITY,目前为5,这些事static final变量)。可通过Thread类中的getPriority()方法获取当前设置的优先级(final int getPriority())。

引入异步,所以在需要时要强制同步。监视器(只能包含一个线程),一旦某个线程遇到监视器,其他所有线程必须等待,直到该线程退出监视器,保护共享资源。java每个对象都有自己的隐式监视器,如果调用同步方法,自动进入隐式监视器,java内置了同步支持。

线程之间的通信,会增加系统开销,允许某个线程进入对象的同步方法,然后进行等待,知道其他线程显式通知这个线程退出为止。

Thread类和Runnable接口。Thread类定义的一些方法(参见http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html),Thread实例就是线程的代理。

2、主线程很重要,因为:其他子线程都是从主线程产生,且通常主线程必须是最后才结束执行的线程,因为他要执行各种关闭动作。主线程是自动创建,但可以通过Thread对象对其进行控制。必须调用currentThread()方法获取对主线程的一个引用,公有静态成员。static Thread currentThread().

例一:获取对当前线程(此处为主线程)的引用,并将引用存在局部变量t中。

class CurrentThreadDemo {
	public static void main(String args[]) {
		//获取对主线程的引用
		Thread t = Thread.currentThread(); //static方法
		
		System.out.println("Current thread: " + t);
		
		t.setName("My Thread");  //更改线程内部名称
		System.out.println("After name change: " + t);
		
		try {
			for(int i = 5; i > 0; i--) {
				System.out.println(i);
				Thread.sleep(100);
			}
		} catch(InterruptedException e) {
			System.out.println("Main Thread interrupted");
		}
	}
}
//output:
Current thread: Thread[main,5,main]  //线程名,优先级,线程所属的线程组的名称
After name change: Thread[My Thread,5,main]
5
4
3
2
1

static void sleep(long milliseconds) throws InterruptedException

static void sleep(long milliseconds, int nanoseconds) throws InterruptedException //精确到纳秒级

final void setName(String threadName)

final String getName() //获取线程的名称

3、创建线程。

两种方法:实现Runnable接口,扩展Thread类本身。

例二:创建线程的最简单的方式:创建实现了Runnable接口的类,public void run().和main线程唯一的区别是:run方法为程序中另外一个并发线程执行建立了入口点。可以调用其他方法,使用其他类,也可声明变量。

class NewThread implements Runnable {
	Thread t; 
	
	NewThread() {
		//create a new,second thread
		//传递this作为第一个参数,以表明希望新线程调用this对象的run()方法。
		t = new Thread(this, "Demo Thread");
		System.out.println("Child thread: " + t);
		t.start(); //start the thread
	}
		
	//this is the entry point for the second thread.
	public void run() {
		try {
			for(int i = 5; i > 0; i--) {
				System.out.println("Child Thread: " + i);
				Thread.sleep(500);
			}
		} catch(InterruptedException e) {
			System.out.println("Child interrupted.");
		}
		System.out.println("Exiting child thread.");
	}
}

class ThreadDemo {
	public static void main(String args[]) {
		new NewThread(); //create a new thread.
		
		try {
			for(int i = 5; i > 0; i--) {
				System.out.println("Main Thread: " + i);
				Thread.sleep(1000);
			}
		} catch(InterruptedException e) {
			System.out.println("Main thread interrupted.");
		}
		System.out.println("Main thread exiting.");
	}
}

//output:
Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.

主线程休眠1000ms,子线程休眠500ms,确保主线程最后结束执行,否则,java运行时系统可能会“挂起”。

例三:创建线程第二种方式:创建一个扩展了Thread的新类,然后创建该类的实例。必须重写run()方法,run()方法时新线程的入口点,还必须调用start()方法以开始新线程的执行。

//create a second thread by extending Thread
class NewThread extends Thread {
	
	NewThread() {
		//create a new,second thread
		super("Demo Thread");
		System.out.println("Child thread: " + this);
		start(); //start the thread
	}
		
	//this is the entry point for the second thread.
	public void run() {
		try {
			for(int i = 5; i > 0; i--) {
				System.out.println("Child Thread: " + i);
				Thread.sleep(500);
			}
		} catch(InterruptedException e) {
			System.out.println("Child interrupted.");
		}
		System.out.println("Exiting child thread.");
	}
}

class ExtendThread {
	public static void main(String args[]) {
		new NewThread(); //create a new thread.
		
		try {
			for(int i = 5; i > 0; i--) {
				System.out.println("Main Thread: " + i);
				Thread.sleep(1000);
			}
		} catch(InterruptedException e) {
			System.out.println("Main thread interrupted.");
		}
		System.out.println("Main thread exiting.");
	}
}

//output:
Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.

如何选择哪种创建方式?Thread类定义了派生类可以重写的几个方法,只有run()必须重写,当然也是实现Runnable接口时需要实现的方法。只有当类正在以某种方式增强或修改时,才应当对类进行扩展。因此,如果不重写Thread类的其他方法,创建子线程最好的方法是简单的实现Runnable接口。此外,通过实现Runnable接口,线程类不需要继承Thread类,从而可以自由继承其他类。

4、创建多个线程。

例四:创建三个子线程。

//create multiple threads.
class NewThread implements Runnable {
	String name;
	Thread t;
	
	NewThread(String threadname) {
		name = threadname;
		t = new Thread(this, name);
		System.out.println("New thread: " + t);
		t.start(); //start the thread
	}
		
	//this is the entry point for the second thread.
	public void run() {
		try {
			for(int i = 5; i > 0; i--) {
				System.out.println(name + ": " + i);
				Thread.sleep(1000);
			}
		} catch(InterruptedException e) {
			System.out.println(name + " interrupted.");
		}
		System.out.println(name + " exiting");
	}
}

class MultiThreadDemo {
	public static void main(String args[]) {
		new NewThread("One"); //start threads.
		new NewThread("Two");
		new NewThread("Three");
		
		try {
			for(int i = 5; i > 0; i--) {
				//wait for other threads to end
				Thread.sleep(10000);
			}
		} catch(InterruptedException e) {
			System.out.println("Main thread interrupted.");
		}
		System.out.println("Main thread exiting.");
	}
}

//output:
New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
One: 5
Two: 5
New thread: Thread[Three,5,main]
Three: 5
Two: 4
One: 4
Three: 4
Two: 3
One: 3
Three: 3
One: 2
Three: 2
Two: 2
One: 1
Three: 1
Two: 1
One exiting
Three exiting
Two exiting
Main thread exiting.

5、使用isAlive()和join()方法。

一个线程如何知道另一个线程何时结束?有两种方法解决,如上。

final boolean isAive() //由Thread类定义

final void join() throws InterrupedException //该方法会一直等待直到调用线程终止,同时允许指定希望等待指定线程终止的最长时间。

例五:join()和isAlive()使用。

class NewThread implements Runnable {
	String name;
	Thread t;
	
	NewThread(String threadname) {
		name = threadname;
		t = new Thread(this, name);
		System.out.println("New thread: " + t);
		t.start(); //start the thread
	}
		
	//this is the entry point for the second thread.
	public void run() {
		try {
			for(int i = 5; i > 0; i--) {
				System.out.println(name + ": " + i);
				Thread.sleep(1000);
			}
		} catch(InterruptedException e) {
			System.out.println(name + " interrupted.");
		}
		System.out.println(name + " exiting");
	}
}

class DemoJoin {
	public static void main(String args[]) {
		NewThread ob1 = new NewThread("One"); //start threads.
		NewThread ob2 = new NewThread("Two");
		NewThread ob3 = new NewThread("Three");
		
		System.out.println("Thread One is alive: " + ob1.t.isAlive());
		System.out.println("Thread Two is alive: " + ob2.t.isAlive());
		System.out.println("Thread Three is alive: " + ob3.t.isAlive());
		
		//wait for threads to finish
		try {
			System.out.println("Waiting for threads to finish.");
			ob1.t.join();
			ob2.t.join();
			ob3.t.join();
		} catch(InterruptedException e) {
			System.out.println("Main thread interrupted.");
		}
		
		System.out.println("Thread One is alive: " + ob1.t.isAlive());
		System.out.println("Thread Two is alive: " + ob2.t.isAlive());
		System.out.println("Thread Three is alive: " + ob3.t.isAlive());
		
		System.out.println("Main thread exiting.");
	}
}

//output:
New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
One: 5
Two: 5
New thread: Thread[Three,5,main]
Thread One is alive: true
Three: 5
Thread Two is alive: true
Thread Three is alive: true
Waiting for threads to finish.
Three: 4
Two: 4
One: 4
Three: 3
Two: 3
One: 3
Three: 2
Two: 2
One: 2
Two: 1
One: 1
Three: 1
Two exiting
Three exiting
One exiting
Thread One is alive: false
Thread Two is alive: false
Thread Three is alive: false
Main thread exiting.

6、线程同步。

只需要调用synchronized关键字修饰过的方法。互斥等待。

例六:同步。

//This program is not synchronized.
class Callme {
	void call(String msg) {
		System.out.print("[" + msg);
		try {
			Thread.sleep(1000);
		} catch(InterruptedException e) {
			System.out.println("Interrupted");
		}
		System.out.println("]");
	}
}

class Caller implements Runnable {
	String msg;
	Callme target;
	Thread t;
	
	public Caller(Callme targ, String s) {
		target = targ; 
		msg = s;
		t = new Thread(this);
		t.start();
	}
	
	public void run() {
		target.call(msg);
	}
}

class Synch {
	public static void main(String args[]) {
		Callme target = new Callme();
		Caller ob1 = new Caller(target, "Hello");
		Caller ob2 = new Caller(target, "Synchronized");
		Caller ob3 = new Caller(target, "World");
		
		//wait for threads to end
		try {
			ob1.t.join();
			ob2.t.join();
			ob3.t.join();
		} catch(InterruptedException e) {
			System.out.println("Interrupted");
		}
	}
}

//output:
[Hello[Synchronized[World]
]
]

//This program is synchronized.
class Callme {
	synchronized void call(String msg) {
		System.out.print("[" + msg);
		try {
			Thread.sleep(1000);
		} catch(InterruptedException e) {
			System.out.println("Interrupted");
		}
		System.out.println("]");
	}
}

class Caller implements Runnable {
	String msg;
	Callme target;
	Thread t;
	
	public Caller(Callme targ, String s) {
		target = targ; 
		msg = s;
		t = new Thread(this);
		t.start();
	}
	
	public void run() {
		target.call(msg);
	}
}

class Synch {
	public static void main(String args[]) {
		Callme target = new Callme();
		Caller ob1 = new Caller(target, "Hello");
		Caller ob2 = new Caller(target, "Synchronized");
		Caller ob3 = new Caller(target, "World");
		
		//wait for threads to end
		try {
			ob1.t.join();
			ob2.t.join();
			ob3.t.join();
		} catch(InterruptedException e) {
			System.out.println("Interrupted");
		}
	}
}

//output:
[Hello]
[World]
[Synchronized]

可以使用synchronized代码块:

class Callme {
	void call(String msg) {
		System.out.print("[" + msg);
		try {
			Thread.sleep(1000);
		} catch(InterruptedException e) {
			System.out.println("Interrupted");
		}
		System.out.println("]");
	}
}

class Caller implements Runnable {
	String msg;
	Callme target;
	Thread t;
	
	public Caller(Callme targ, String s) {
		target = targ; 
		msg = s;
		t = new Thread(this);
		t.start();
	}
	
	public void run() {
		synchronized(target) { //synchronized block
			target.call(msg);
		}
	}
}

class Synch {
	public static void main(String args[]) {
		Callme target = new Callme();
		Caller ob1 = new Caller(target, "Hello");
		Caller ob2 = new Caller(target, "Synchronized");
		Caller ob3 = new Caller(target, "World");
		
		//wait for threads to end
		try {
			ob1.t.join();
			ob2.t.join();
			ob3.t.join();
		} catch(InterruptedException e) {
			System.out.println("Interrupted");
		}
	}
}

//output:
[Hello]
[World]
[Synchronized]

一旦线程进入一个实例的同步方法,其他线程不能进入相同实例的 任何 同步方法。但是仍可继续调用同一实例的非同步部分。

7、线程间通信。

wait()方法通知调用线程放弃监视器并进入休眠,直到其他一些线程进入同一个监视器并调用notify()或notifyAll()方法。

notify()方法唤醒调用相同对象的wait()方法的线程。

notifyAll()方法唤醒调用相同对象的wait()方法的所有线程,其中的一个线程将得到访问授权。

都是在Object类中定义。wait()方法还有另一种形式,允许指定等待的时间间隔。假唤醒

final void wait() throws InterruptedException

final void notify()

final void notifyAll()

例七:线程间通信。

//A correct implementation of a producer and consumer.
class Q {
	int n;
	boolean valueSet = false;
	
	synchronized int get() {
		while(!valueSet) {
			try {
				wait();
			} catch(InterruptedException e) {
				System.out.println("InterruptedException caught");
			}
		}	
		
		System.out.println("Got: " + n);
		valueSet = false;
		notify();
		return n;
	}
	
	synchronized void put(int n) {
		while(valueSet) {
			try {
				wait();
			} catch(InterruptedException e) {
				System.out.println("InterruptedException caught");
			}
		}
		
		this.n = n;
		valueSet = true;
		System.out.println("Put: " + n);
		notify();
	}
}

class Producer implements Runnable {
	Q q;
	
	Producer(Q q) {
		this.q = q;
		new Thread(this, "Producer").start();
	}
	
	public void run() {
		int i = 0;
		while(true) {
			q.put(i++);
		}
	}
}

class Consumer implements Runnable {
	Q q;
	
	Consumer(Q q) {
		this.q = q;
		new Thread(this, "Consumer").start();
	}
	
	public void run() {
		while(true) {
			q.get();
		}
	}
}

class PCFixed {
	public static void main(String args[]) {
		Q q = new Q();
		new Producer(q);
		new Consumer(q);
		
		System.out.println("Press Control-C to stop.");
	}
}

//output:
Put: 0
Press Control-C to stop.
Got: 0
Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4
Got: 4
Put: 5
Got: 5
Put: 6
Got: 6
Put: 7
Got: 7
Put: 8
Got: 8
Put: 9
Got: 9
Put: 10
Got: 10
Put: 11
Got: 11

8、死锁。

例八:死锁。

//an example of deadlock
class A {
	synchronized void foo(B b) {
		String name = Thread.currentThread().getName();
		
		System.out.println(name + "entered A.foo");
		
		try {
			Thread.sleep(1000);
		} catch(Exception e) {
			System.out.println("A Interrupted");
		}
		
		System.out.println(name + " trying to call B.last()");
		b.last();
	}
	
	synchronized void last() {
		System.out.println("Inside A.last");
	}
}

class B {
	synchronized void bar(A a) {
		String name = Thread.currentThread().getName();
		System.out.println(name + "entered B.bar");
		
		try {
			Thread.sleep(1000);
		} catch(InterruptedException e) {
			System.out.println("B Interrupted");
		}
		
		System.out.println(name + "trying to call A.last()");
		a.last();
	}
	
	synchronized void last() {
		System.out.println("Inside A.last");
	}
}

class Deadlock implements Runnable {
	A a = new A();
	B b = new B();
	
	Deadlock() {
		Thread.currentThread().setName("MainThread");
		Thread t = new Thread(this, "RacingThread");
		t.start();
		
		a.foo(b);
		System.out.println("Back in main thread");
	}
	
	public void run() {
		b.bar(a);
		System.out.println("Back in other thread");
	}
	
	public static void main(String args[]) {
		new Deadlock();
	}
}

//output:
MainThreadentered A.foo
RacingThreadentered B.bar
MainThread trying to call B.last()
RacingThreadtrying to call A.last()

9、挂起、恢复和停止线程。

例九:

//Suspending and resuming a thread the modern way.
class NewThread implements Runnable {
	String name;
	Thread t;
	boolean suspendFlag;
	
	NewThread(String threadname) {
		name = threadname;
		t = new Thread(this, name);
		System.out.println("New thread: " + t);
		suspendFlag = false;
		t.start();
	}
	
	public void run() {
		try {
			for(int i = 15; i > 0; i--) {
				System.out.println(name + ": " + i);
				Thread.sleep(200);
				synchronized(this) {
					while(suspendFlag) {
						wait();
					}
				}
			}
		} catch(InterruptedException e) {
			System.out.println(name + " interrupted.");
		}
		
		System.out.println(name + "exiting.");
	}
	
	synchronized void mysuspend() {
		suspendFlag = true;
	}
	
	synchronized void myresume() {
		suspendFlag = false;
		notify();
	}
}

class SuspendResume {
	public static void main(String args[]) {
		NewThread ob1 = new NewThread("One");
		NewThread ob2 = new NewThread("Two");
		
		try {
			Thread.sleep(1000);
			ob1.mysuspend();
			System.out.println("Suspending thread One");
			Thread.sleep(1000);
			ob1.myresume();
			System.out.println("Resuming thread One");
			
			ob2.mysuspend();
			System.out.println("Suspending thread Two");
			Thread.sleep(1000);
			ob2.myresume();
			System.out.println("Resuming thread Two");
		} catch(InterruptedException e) {
			System.out.println("Main thread Interrupted");
		}
		
		//wait for threads to end
		try {
			System.out.println("Waiting for threads to finish.");
			ob1.t.join();
			ob2.t.join();
		} catch(InterruptedException e) {
			System.out.println("Main thread Interrupted");
		}
		
		System.out.println("Main thread exiting.");
	
	}

}

//output:
New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
One: 15
Two: 15
Two: 14
One: 14
Two: 13
One: 13
One: 12
Two: 12
One: 11
Two: 11
Suspending thread One
Two: 10
Two: 9
Two: 8
Two: 7
Two: 6
One: 10
Resuming thread One
Suspending thread Two
One: 9
One: 8
One: 7
One: 6
One: 5
Two: 5
Resuming thread Two
Waiting for threads to finish.
One: 4
Two: 4
One: 3
Two: 3
One: 2
Two: 2
One: 1
Two: 1
Oneexiting.
Twoexiting.
Main thread exiting.

10、获取线程的状态。

Thread.State getState() //返回Thread.State类型的值,指示在调用该方法时线程所处的状态

Thread.State ts = thrd.getState();

if(ts == Thread.State.RUNNABLE) ...

在调用getState()后,线程的状态可能会发生变化,因此在具体环境中,可能无法反应滞后一段较短时间内线程的实际状态。故,getState()方法的目标不是提供一种同步线程的方法,而主要用于调试或者显示线程的运行时特征。

getState()方法的返回值

BLOCKED 线程因为正在等待需要的锁而挂起执行

NEW 线程还没有开始运行

RUNNABLE 线程要么当前正在执行,要么访问CPU的访问权之后执行

TERMINATED 线程已经完成执行

TIMED_WAITING    线程挂起执行一段指定的时间,如调用sleep()时或者wait()或join()方法的暂停版时,进入

WAITING 线程因为等待某些动作而挂起执行。如调用非暂停版的wait()或join()方法而等待时。


于2013/04/11

你可能感兴趣的:(Java学习)