多线程程序设计
写在之前
以下是《Java8编程入门官方教程》中的一些知识,如有错误,烦请指正。涉及的程序如需下载请移步http://down1.tupwk.com.cn/qhwkdownpage/978-7-302-38738-1.zip
多线程
多任务包括:基于进程的多任务和基于线程的多任务。进程是正在执行的程序,相当于计算机允许同时运行多个程序的功能;线程是最小的可分派代码单元,一个程序可以一次执行多个任务,比如文本编辑器可以在打印的同时格式化文本。
单核系统中并发执行的线程共享CPU,每个线程都收到一个CPU时间片;多核系统中,多个线程可以同时执行。多线程的功能在两个系统中都可以实现。
Thread类和Runnable接口
方法 | 含义 |
---|---|
final String getName() | 获取线程名 |
final int getPriority() | 获取线程优先级 |
final boolean isAlive() | 确定线程是否仍在运行 |
final void join() | 等待线程终止 |
static void sleep(long milliseconds) | 按照指定的时间挂起线程,以毫秒为单位 |
void start() | 通过调用run方法启动线程 |
void run() | 线程的进入点 |
线程创建
两种方法:都要用Thread类来实例化、访问、控制线程,仅仅是创建不同。
- 实现Runnable接口
- 扩展Thread类
比较:一般仅在通过某些方式增强或者修改类的时候才扩展这些类,因此如果不重写Thread的任何其他方法,最好事先Runnable接口。另外实现Runnable接口可以让线程继承除Thread类外的其他类。
Runnable接口只定义了run方法,在run方法中可以调用其他方法,使用其他类,像主线程一样声明变量。具体的方法通过程序来说明。
// 通过实现Runnable接口创建进程
class MyThread implements Runnable {
String thrdName;
MyThread(String name) {
thrdName = name;
}
// Entry point of thread.
public void run() {
System.out.println(thrdName + " starting.");
try {
for(int count=0; count < 10; count++) {
Thread.sleep(400);
System.out.println("In " + thrdName +
", count is " + count);
}
}
catch(InterruptedException exc) {
System.out.println(thrdName + " interrupted.");
}
System.out.println(thrdName + " terminating.");
}
}
class UseThreads {
public static void main(String args[]) {
System.out.println("Main thread starting.");
// 1.创建一个可运行的线程对象
MyThread mt = new MyThread("Child #1");
// 2.在该对象上构造一个线程
Thread newThrd = new Thread(mt);
// 3.开始运行线程
newThrd.start();
for(int i=0; i<50; i++) {
System.out.print(".");
try {
Thread.sleep(100);//主线程main延迟了5秒,线程mt延迟了4秒,确保main在mt结束之后才终止
}
catch(InterruptedException exc) {
System.out.println("Main thread interrupted.");
}
}
System.out.println("Main thread ending.");
}
}
改进:MyThread类没必要存储线程名,可以在创建时就为其命名。Thread(Runnable threadob, String name)
//改进版
class MyThread implements Runnable {
Thread thrd;
// 建立一个新进程
MyThread(String name) {
thrd = new Thread(this, name);//创建时就命名
thrd.start(); // 开始进程
}
// Begin execution of new thread.
public void run() {
System.out.println(thrd.getName() + " starting.");
try {
for(int count=0; count<10; count++) {
Thread.sleep(400);
System.out.println("In " + thrd.getName() +
", count is " + count);
}
}
catch(InterruptedException exc) {
System.out.println(thrd.getName() + " interrupted.");
}
System.out.println(thrd.getName() + " terminating.");
}
}
class UseThreadsImproved {
public static void main(String args[]) {
System.out.println("Main thread starting.");
MyThread mt = new MyThread("Child #1");s//改进后创建时就启动进程
for(int i=0; i < 50; i++) {
System.out.print(".");
try {
Thread.sleep(100);
}
catch(InterruptedException exc) {
System.out.println("Main thread interrupted.");
}
}
System.out.println("Main thread ending.");
}
}
另一种方法:扩展Thread,必须重写作为新建成进入点的run方法。
class MyThread extends Thread {
// 建立一个新的线程.
MyThread(String name) {
super(name); // 线程命名
start(); // 开始线程
}
// 线程运行
public void run() {
System.out.println(getName() + " starting.");
try {
for(int count=0; count < 10; count++) {
Thread.sleep(400);
System.out.println("In " + getName() +
", count is " + count);
}
}
catch(InterruptedException exc) {
System.out.println(getName() + " interrupted.");
}
System.out.println(getName() + " terminating.");
}
}
class ExtendThread {
public static void main(String args[]) {
System.out.println("Main thread starting.");
MyThread mt = new MyThread("Child #1");
for(int i=0; i < 50; i++) {
System.out.print(".");
try {
Thread.sleep(100);
}
catch(InterruptedException exc) {
System.out.println("Main thread interrupted.");
}
}
System.out.println("Main thread ending.");
}
}
创建多个线程
class MyThread implements Runnable {
Thread thrd;
// 构造线程
MyThread(String name) {
thrd = new Thread(this, name);
thrd.start(); // 开始线程
}
// 执行线程
public void run() {
System.out.println(thrd.getName() + " starting.");
try {
for(int count=0; count < 10; count++) {
Thread.sleep(400);
System.out.println("In " + thrd.getName() +
", count is " + count);
}
}
catch(InterruptedException exc) {
System.out.println(thrd.getName() + " interrupted.");
}
System.out.println(thrd.getName() + " terminating.");
}
}
class MoreThreads {
public static void main(String args[]) {
System.out.println("Main thread starting.");
MyThread mt1 = new MyThread("Child #1");//创建并开始执行3个线程
MyThread mt2 = new MyThread("Child #2");
MyThread mt3 = new MyThread("Child #3");
for(int i=0; i < 50; i++) {
System.out.print(".");
try {
Thread.sleep(100);
}
catch(InterruptedException exc) {
System.out.println("Main thread interrupted.");
}
}
System.out.println("Main thread ending.");
}
}
确定线程的结束
两种方法:
final boolean isAlive()
class MoreThreads {
public static void main(String args[]) {
System.out.println("Main thread starting.");
MyThread mt1 = new MyThread("Child #1");
MyThread mt2 = new MyThread("Child #2");
MyThread mt3 = new MyThread("Child #3");
do {
System.out.print(".");
try {
Thread.sleep(100);
}
catch(InterruptedException exc) {
System.out.println("Main thread interrupted.");
}
} while (mt1.thrd.isAlive() ||
mt2.thrd.isAlive() ||
mt3.thrd.isAlive()); //使用Alive等待所有线程终止
System.out.println("Main thread ending.");
}
}
final void join() Throws InterruptedException
等待,直到调用的线程终止
class MyThread implements Runnable {
Thread thrd;
// Construct a new thread.
MyThread(String name) {
thrd = new Thread(this, name);
thrd.start(); // start the thread
}
// Begin execution of new thread.
public void run() {
System.out.println(thrd.getName() + " starting.");
try {
for(int count=0; count < 10; count++) {
Thread.sleep(400);
System.out.println("In " + thrd.getName() +
", count is " + count);
}
}
catch(InterruptedException exc) {
System.out.println(thrd.getName() + " interrupted.");
}
System.out.println(thrd.getName() + " terminating.");
}
}
class JoinThreads {
public static void main(String args[]) {
System.out.println("Main thread starting.");
MyThread mt1 = new MyThread("Child #1");
MyThread mt2 = new MyThread("Child #2");
MyThread mt3 = new MyThread("Child #3");
try {
mt1.thrd.join();//等待,直到线程中终结,下同
System.out.println("Child #1 joined.");
mt2.thrd.join();
System.out.println("Child #2 joined.");
mt3.thrd.join();
System.out.println("Child #3 joined.");
}
catch(InterruptedException exc) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread ending.");
}
}
线程优先级
可以通过Thread的成员方法来修改线程的优先级。
final void setPriority(int level)
level的值必须在MIN_PRIORITY
和MAX_PRIORITY
的范围内,即1-10.优先级定义为static final
变量。
可以通过Thread的成员方法获取当前优先级设置。
final int getPriority
//线程的优先级
class Priority implements Runnable {
int count;
Thread thrd;
static boolean stop = false;
static String currentName;
/* Construct a new thread. Notice that this
constructor does not actually start the
threads running. */
Priority(String name) {
thrd = new Thread(this, name);
count = 0;
currentName = name;
}
// Begin execution of new thread.
public void run() {
System.out.println(thrd.getName() + " starting.");
do {
count++;
if(currentName.compareTo(thrd.getName()) != 0) {
currentName = thrd.getName();
System.out.println("In " + currentName);
}
} while(stop == false && count < 10000000);
stop = true;
System.out.println("\n" + thrd.getName() +
" terminating.");
}
}
class PriorityDemo {
public static void main(String args[]) {
Priority mt1 = new Priority("High Priority");
Priority mt2 = new Priority("Low Priority");
// set the priorities
mt1.thrd.setPriority(Thread.NORM_PRIORITY+2);
mt2.thrd.setPriority(Thread.NORM_PRIORITY-2);
// start the threads
mt1.thrd.start();
mt2.thrd.start();
try {
mt1.thrd.join(); //等待线程结束
mt2.thrd.join();
}
catch(InterruptedException exc) {
System.out.println("Main thread interrupted.");
}
System.out.println("\nHigh priority thread counted to " +
mt1.count);
System.out.println("Low priority thread counted to " +
mt2.count);
}
}
同步
同步:控制对象访问的监视器,监视器通过实现“锁”来工作。当一个对象被一个线程锁住后,其他线程就不能访问该对象。当该线程退出时,要为对象解锁,使其他进程可以访问他。有两种同步的方法。
通过synchronized
关键字修改方法来同步对方法的访问。当调用方法时,调用线程进入对象监视器,对象监视器锁住对象。对象被锁的同时,其他线程不能进入方法,也不能进入対象定义的其他同步方法。当线程从方法返回时,监视器为对象解锁,允许下一个进程使用对象。
//使用同步方法控制访问
class SumArray {
private int sum;
synchronized int sumArray(int nums[]) { //sumArray()被同步
sum = 0; // reset sum
for(int i=0; i<nums.length; i++) {
sum += nums[i];
System.out.println("Running total for " +
Thread.currentThread().getName() +
" is " + sum);
try {
Thread.sleep(10); // allow task-switch
}
catch(InterruptedException exc) {
System.out.println("Thread interrupted.");
}
}
return sum;
}
}
class MyThread implements Runnable {
Thread thrd;
static SumArray sa = new SumArray();
int a[];
int answer;
// Construct a new thread.
MyThread(String name, int nums[]) {
thrd = new Thread(this, name);
a = nums;
thrd.start(); // start the thread
}
// Begin execution of new thread.
public void run() {
int sum;
System.out.println(thrd.getName() + " starting.");
answer = sa.sumArray(a);
System.out.println("Sum for " + thrd.getName() +
" is " + answer);
System.out.println(thrd.getName() + " terminating.");
}
}
class Sync {
public static void main(String args[]) {
int a[] = {1, 2, 3, 4, 5};
MyThread mt1 = new MyThread("Child #1", a);
MyThread mt2 = new MyThread("Child #2", a);
try {
mt1.thrd.join();
mt2.thrd.join();
}
catch(InterruptedException exc) {
System.out.println("Main thread interrupted.");
}
}
}
当上面提出的方法在无法访问源代码时,可以将对这种类定义的方法的调用放入synchronized
代码块中。
// Use a synchronized block to control access to SumArray.
class SumArray {
private int sum;
int sumArray(int nums[]) { //没有同步!!
sum = 0; // reset sum
for(int i=0; i<nums.length; i++) {
sum += nums[i];
System.out.println("Running total for " +
Thread.currentThread().getName() +
" is " + sum);
try {
Thread.sleep(10); // allow task-switch
}
catch(InterruptedException exc) {
System.out.println("Thread interrupted.");
}
}
return sum;
}
}
class MyThread implements Runnable {
Thread thrd;
static SumArray sa = new SumArray();
int a[];
int answer;
// Construct a new thread.
MyThread(String name, int nums[]) {
thrd = new Thread(this, name);
a = nums;
thrd.start(); // start the thread
}
// Begin execution of new thread.
public void run() {
int sum;
System.out.println(thrd.getName() + " starting.");
// synchronize calls to sumArray()
synchronized(sa) { //对sumArray的调用被同步
answer = sa.sumArray(a);
}
System.out.println("Sum for " + thrd.getName() +
" is " + answer);
System.out.println(thrd.getName() + " terminating.");
}
}
class Sync {
public static void main(String args[]) {
int a[] = {1, 2, 3, 4, 5};
MyThread mt1 = new MyThread("Child #1", a);
MyThread mt2 = new MyThread("Child #2", a);
try {
mt1.thrd.join();
mt2.thrd.join();
} catch(InterruptedException exc) {
System.out.println("Main thread interrupted.");
}
}
}
线程通信
一个线程可以通知另一个线程它被阻塞,而其他进程也可以通知它继续执行。Java使用wait()
、notify()
、notifyAll()
支持进程间通信。三个方法是Object类实现的,是所有对象的一部分,只能在同步环境中被调用。当一个线程暂时阻塞无法运行,它调用wait()
,导致进程睡眠,对象的监视器被释放,允许其他线程使用该对象。过一段时间后,当另一个线程进入这个监视器的时候,调用notify()
或notifyAll()
,睡眠进程被唤醒。
final void wait() throws InterruptedException//等待,直到被通知
final void wait(long millis) throws InterruptedException//或者等待一定时间后
final void wait(long millis,int nanos) throws InterruptedException
final void notify() //恢复一个等待线程
final void notifyAll() //通知所有线程
一个使用wait()和notify()
的例子
//比较难,请多次阅读或者运行
class TickTock {
String state; // contains the state of the clock
synchronized void tick(boolean running) {
if(!running) { // stop the clock
state = "ticked";
notify(); // notify any waiting threads
return;
}
System.out.print("Tick ");
state = "ticked"; // set the current state to ticked
notify(); // let tock() run
try {
while(!state.equals("tocked"))
wait(); // wait for tock() to complete
}
catch(InterruptedException exc) {
System.out.println("Thread interrupted.");
}
}
synchronized void tock(boolean running) {
if(!running) { // stop the clock
state = "tocked";
notify(); // notify any waiting threads
return;
}
System.out.println("Tock");
state = "tocked"; // set the current state to tocked
notify(); // let tick() run
try {
while(!state.equals("ticked"))
wait(); // wait for tick to complete
}
catch(InterruptedException exc) {
System.out.println("Thread interrupted.");
}
}
}
class MyThread implements Runnable {
Thread thrd;
TickTock ttOb;
// Construct a new thread.
MyThread(String name, TickTock tt) {
thrd = new Thread(this, name);
ttOb = tt;
thrd.start(); // start the thread
}
// Begin execution of new thread.
public void run() {
if(thrd.getName().compareTo("Tick") == 0) {
for(int is
}
}
}
class ThreadCom {
public static void main(String args[]) {
TickTock tt = new TickTock();
MyThread mt1 = new MyThread("Tick", tt);
MyThread mt2 = new MyThread("Tock", tt);
try {
mt1.thrd.join();
mt2.thrd.join();
} catch(InterruptedException exc) {
System.out.println("Main thread interrupted.");
}
}
}
死锁:一个线程等待另一个线程来做某事,而后者却又在等待前者。这就像两个过于礼貌的谦谦君子,都坚持让对方先通过大门。
竞争:当两个或多个线程尝试同时访问共享资源,但是没有进行合适的同步时,就会发生竞争条件。
挂起、继续执行、停止
一个标志变量用于设置挂起和继续执行,分别是:suspend
和running
一个标志变量用于停止,设置为stop
//挂起、继续执行、停止
class MyThread implements Runnable {
Thread thrd;
boolean suspended; //当设置为true时挂起线程
boolean stopped; //当设置为true时终止线程
MyThread(String name) {
thrd = new Thread(this, name);
suspended = false;
stopped = false;
thrd.start();
}
// This is the entry point for thread.
public void run() {
System.out.println(thrd.getName() + " starting.");
try {
for(int i = 1; i < 1000; i++) {
System.out.print(i + " ");
if((i%10)==0) {
System.out.println();
Thread.sleep(250);
}
// Use synchronized block to check suspended and stopped.
synchronized(this) {
while(suspended) {
wait();
}
if(stopped) break;
}
}
} catch (InterruptedException exc) {
System.out.println(thrd.getName() + " interrupted.");
}
System.out.println(thrd.getName() + " exiting.");
}
// Stop the thread.
synchronized void mystop() {
stopped = true;
// The following ensures that a suspended thread can be stopped.
suspended = false;
notify();
}
// Suspend the thread.
synchronized void mysuspend() {++++++++++
suspended = true;
}
// Resume the thread.
synchronized void myresume() {
suspended = false;
notify();
}
}
class Suspend {
public static void main(String args[]) {
MyThread ob1 = new MyThread("My Thread");
try {
Thread.sleep(1000); // let ob1 thread start executing
ob1.mysuspend();
System.out.println("Suspending thread.");
Thread.sleep(1000);
ob1.myresume();
System.out.println("Resuming thread.");
Thread.sleep(1000);
ob1.mysuspend();
System.out.println("Suspending thread.");
Thread.sleep(1000);
ob1.myresume();
System.out.println("Resuming thread.");
Thread.sleep(1000);
ob1.mysuspend();
System.out.println("Stopping thread.");
ob1.mystop();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
// wait for thread to finish
try {
ob1.thrd.join();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
}
主线程
class UseMain {
public static void main(String args[]) {
Thread thrd;
// Get the main thread.
thrd = Thread.currentThread();
// Display main thread's name.
System.out.println("Main thread is called: " +
thrd.getName());
// Display main thread's priority.
System.out.println("Priority: " +
thrd.getPriority());
System.out.println();
// Set the name and priority.
System.out.println("Setting name and priority.\n");
thrd.setName("Thread #1");
thrd.setPriority(Thread.NORM_PRIORITY+3);
System.out.println("Main thread is now called: " +
thrd.getName());
System.out.println("Priority is now: " +
thrd.getPriority());
}
}