7-18 2,512 views
Java支持多线程,可以通过继续Thread类或实现Runnable接口定义线程类,并在该类中重写run方法。
一个简单的Java线程类MyThread如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.wt.testThread; public class MyThread extends Thread{ public void run() { int i = 0; while (true) { i++; System.out.println("MyThread Processing --> "+i); try { Thread.sleep(500); } catch (InterruptedException e) {} } } public static void main(String args[]) { MyThread thread = new MyThread(); thread.start(); } } |
在MyThread的run方法中,每隔500ms(Thread.sleep(500);)输出一次信息。在主函数中,新建MyThread实例对象,并使用对象的start方法启动该线程实例。程序输出结果部分如下所示。
MyThread Processing –> 1
MyThread Processing –> 2
MyThread Processing –> 3
多线程的同步
假设现在有两件工具,三个工人,每个工人工作时需要同时使用这两件工具。使用Java多线程模拟上述情景,使用线程类WorkThread表示工人,使用ToolBox表示两件工具所在的工具箱,如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
class ToolBox{ //t1Owner,t2Owner分别表示正在使用该工具的工人名 private String t1Owner; private String t2Owner; //useTool表示某位工人取得工具并使用 public void useTool(String workerName) throws InterruptedException { t1Owner = workerName; Thread.sleep(100); t2Owner = workerName; Thread.sleep(100); checkTool(); } //useTool检查工具是否正在被同一个工人使用 public void checkTool() { if (!t1Owner.equals(t2Owner)){ System.out.println("*Wrong*: Tool1:"+t1Owner+"\t Tool2:"+t2Owner); } else{ System.out.println("*Right*: Tool1:"+t1Owner+"\t Tool2:"+t2Owner); } } } public class WorkerThread extends Thread{ private ToolBox toolBox; private String workerName; public WorkerThread(String workerName,ToolBox toolBox) { super(); this.workerName = workerName; this.toolBox = toolBox; } public void run() { //工人每次休息1秒,然后使用工具工作 while(true) { try { Thread.sleep(1000); toolBox.useTool(workerName); } catch (InterruptedException e) {} } } } |
主函数如下所示,其中ToolBox类实例toolBox表示工人共用的工具箱,通过WorkerThread类的构造函数构造三个工人线程类,并传入工人姓名和toolBox,启动线程。
1 2 3 4 5 6 7 8 9 |
public static void main(String args[]) { //工人共用的工具箱 ToolBox toolBox = new ToolBox(); //三个工人开始工作 new WorkerThread("Tom",toolBox).start(); new WorkerThread("Jack",toolBox).start(); new WorkerThread("Bob",toolBox).start(); } |
执行结果部分如下所示。
*Right*: Tool1:Bob Tool2:Bob
*Right*: Tool1:Bob Tool2:Bob
*Wrong*: Tool1:Bob Tool2:Jack
*Wrong*: Tool1:Bob Tool2:Jack
*Wrong*: Tool1:Bob Tool2:Jack
*Right*: Tool1:Jack Tool2:Jack
*Right*: Tool1:Jack Tool2:Jack
*Right*: Tool1:Jack Tool2:Jack
*Wrong*: Tool1:Jack Tool2:Tom
*Wrong*: Tool1:Jack Tool2:Tom
*Wrong*: Tool1:Jack Tool2:Tom
*Right*: Tool1:Tom Tool2:Tom
可以看出,由于三个工人线程类共享使用工具箱中的工具,导致存在对于工具使用的竞争。由于ToolBox中useTool方法的代码(即工人使用工具)存在上述多线程之间的资源竞争,因此将其称为临界区(Critical Section)。临界区如下所示。
1 2 3 4 5 |
t1Owner = workerName; Thread.sleep(100); t2Owner = workerName; Thread.sleep(100); checkTool(); |
对于上述临界区中的代码,需要实现同步,即在一个线程中,要么都执行,要么都不执行。在Java中,可以使用关键字synchronized实现同步。synchronized的使用方法有两种:
1)对于需要同步的共享实例对象,将synchronized添加为方法的修饰符,如下所示。
1 |
public synchronized void useTool(String workerName) throws InterruptedException |
2)将需要同步的临界区代码放入synchronized(this){}中,如下所示。
1 2 3 4 5 6 7 8 |
synchronized(this) { t1Owner = workerName; Thread.sleep(100); t2Owner = workerName; Thread.sleep(100); checkTool(); } |
使用synchronized同步后,重新执行原主函数,得到正确执行结果。
*Right*: Tool1:Tom Tool2:Tom
*Right*: Tool1:Bob Tool2:Bob
*Right*: Tool1:Jack Tool2:Jack
*Right*: Tool1:Tom Tool2:Tom
*Right*: Tool1:Bob Tool2:Bob
*Right*: Tool1:Jack Tool2:Jack
*Right*: Tool1:Tom Tool2:Tom
*Right*: Tool1:Bob Tool2:Bob
*Right*: Tool1:Jack Tool2:Jack
*Right*: Tool1:Tom Tool2:Tom
*Right*: Tool1:Bob Tool2:Bob
*Right*: Tool1:Jack Tool2:Jack
*Right*: Tool1:Tom Tool2:Tom
*Right*: Tool1:Bob Tool2:Bob
*Right*: Tool1:Jack Tool2:Jack
*Right*: Tool1:Tom Tool2:Tom
版权属于: 我爱我家
转载时必须以链接形式注明原始出处及本声明。