Java 多线程编程
Java 给多线程编程提供了内置的支持。一个多线程程序包含两个或多个能并发运行的部分。程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径。
多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。
这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守候线程都结束运行后才能结束。
多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。
一个线程的生命周期
线程是一个动态执行的过程,它也有一个从产生到死亡的过程。
下图显示了一个线程完整的生命周期。
新建状态:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。就绪状态:
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。运行状态:
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
a): 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
b): 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
c):其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。死亡状态:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
线程的优先级
每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。
Java 线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。
默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。
具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。
创建一个线程
Java 提供了三种创建线程的方法:
- 通过实现 Runnable 接口;
- 通过继承 Thread 类本身;
- 通过 Callable 和 Future 创建线程。
1 通过实现 Runnable 接口来创建线程
- 推荐使用Runnable创建线程
1: 避免单继承的局限性
2: 便于共享资源
创建一个线程,最简单的方法是创建一个实现 Runnable 接口的类。
为了实现 Runnable,一个类只需要执行一个方法调用 run(),声明如下:
public void run()
你可以重写该方法,重要的是理解的 run() 可以调用其他方法,使用其他类,并声明变量,就像主线程一样。
在创建一个实现 Runnable 接口的类之后,你可以在类中实例化一个线程对象。
Thread 定义了几个构造方法,下面的这个是我们经常使用的:
Thread(Runnable threadOb,String threadName);
这里,threadOb 是一个实现 Runnable 接口的类的实例,并且 threadName 指定新线程的名字。
新线程创建之后,你调用它的 start() 方法它才会运行。
void start();
- 使用Runnable 接口来创建线程第一种
package CreateRunnable2;
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println(threadName + "创建成功!");
}
public void run() {
System.out.println(threadName + "开始RUN!");
try {
for(int i = 4; i > 0; i--) {
System.out.println(threadName + "正在运行, " + i);
// 让线程睡眠一会
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println( threadName + " 运行结束");
}
public void start () {
System.out.println(threadName + "调用STRAT方法成功");
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestRunnable {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "第一个线程");
R1.start();
RunnableDemo R2 = new RunnableDemo( "第二个线程#########");
R2.start();
}
}
运行
第一个线程创建成功!
第一个线程调用STRAT方法成功
第二个线程#########创建成功!
第二个线程#########调用STRAT方法成功
第一个线程开始RUN!
第一个线程正在运行, 4
第二个线程#########开始RUN!
第二个线程#########正在运行, 4
第二个线程#########正在运行, 3
第一个线程正在运行, 3
第二个线程#########正在运行, 2
第一个线程正在运行, 2
第二个线程#########正在运行, 1
第一个线程正在运行, 1
第二个线程######### 运行结束
第一个线程 运行结束
- 使用Runnable 接口来创建线程第二种
package CreateRunnable2;
/*
* 使用Runnable创建线程
* 1: 类 实现Runnable接口 + 重写run();
* 2: 启动多线程
* 1) 创建真实角色
* 2) 创建代理角色 + 真实角色引用
* 3) 调用start() 启动线程
*
* 推荐使用Runnable创建线程
* 1: 避免单继承的局限性
* 2: 便于共享资源
*/
class MyRunnable implements Runnable{
@Override
public void run() {
try {
for(int i=0;i<10;i++){
Thread.sleep(50);
System.out.println("敲HelloWorld");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TestRunnable2 {
public static void main(String[] args) {
try {
//1) 创建真实角色
MyRunnable run = new MyRunnable();
//2) 创建代理角色 + 真实角色引用
Thread th = new Thread(run);
//3) 调用start() 启动线程
th.start();
for(int i=0;i<10;i++){
Thread.sleep(50);
System.out.println("聊天");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行
聊天
敲HelloWorld
敲HelloWorld
聊天
敲HelloWorld
聊天
聊天
敲HelloWorld
聊天
敲HelloWorld
聊天
敲HelloWorld
聊天
敲HelloWorld
聊天
敲HelloWorld
聊天
敲HelloWorld
敲HelloWorld
聊天
2 通过继承Thread来创建线程
创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。
继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。
该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。
- 通过继承Thread来创建线程____第一种
package CreateRunnable;
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// 让线程睡醒一会
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo( "Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo( "Thread-2");
T2.start();
}
}
运行
Thread-1创建成功!
Thread-1调用STRAT方法成功
Thread-2创建成功!
Thread-1开始RUN!
Thread-2调用STRAT方法成功
Thread-1正在运行, 4
Thread-2开始RUN!
Thread-2正在运行, 4
Thread-2正在运行, 3
Thread-1正在运行, 3
Thread-2正在运行, 2
Thread-1正在运行, 2
Thread-1正在运行, 1
Thread-2正在运行, 1
Thread-1 运行结束
Thread-2 运行结束
- 通过继承Thread来创建线程____第二种
package CreateRunnable;
/*
* 模拟龟兔赛跑
* 1 创建多线程 继承Thread + 重写run(线程体)
* 2 使用线程:创建子类对象-->调用start()方法
*/
public class TestThread2 {
public static void main(String[] args) {
try {
//创建子类对象
Rabbit rab = new Rabbit();
Tortoise tor = new Tortoise();
//调用start方法(不能调用run()方法)
//如果此处调用rab.run()方法,必须把兔子执行完后,才会向下执行
rab.start();
tor.start();
for(int i=0;i<10;i++){
Thread.sleep(50);
System.out.println("我是main方法" + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//兔子类
class Rabbit extends Thread {
@Override
public void run() {
try {
for(int i=0;i<10;i++){
Thread.sleep(50);
System.out.println("兔子跑了" + i + "***********米");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//乌龟类
class Tortoise extends Thread{
@Override
public void run() {
try {
//线程体
for(int i=0;i<10;i++){
Thread.sleep(50);
System.out.println("乌龟跑了"+ i + "步");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行
我是main方法0
乌龟跑了0步
兔子跑了0***********米
乌龟跑了1步
兔子跑了1***********米
我是main方法1
兔子跑了2***********米
我是main方法2
乌龟跑了2步
乌龟跑了3步
兔子跑了3***********米
我是main方法3
乌龟跑了4步
我是main方法4
兔子跑了4***********米
兔子跑了5***********米
我是main方法5
乌龟跑了5步
兔子跑了6***********米
乌龟跑了6步
我是main方法6
兔子跑了7***********米
乌龟跑了7步
我是main方法7
兔子跑了8***********米
乌龟跑了8步
我是main方法8
兔子跑了9***********米
我是main方法9
乌龟跑了9步
通过 Callable 和 Future 创建线程(了解即可,用不到)
- 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
- 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
- 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
- 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
- 通过 Callable创建线程____第一种方法
package CreateRunnable3;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class TestCallable2 implements Callable {
public static void main(String[] args) {
TestCallable2 ctt = new TestCallable2();
FutureTask ft = new FutureTask<>(ctt);
for(int i = 0;i < 100;i++) {
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
if(i==20) {
new Thread(ft,"有返回值的线程").start();
}
}
try {
System.out.println("子线程的返回值:"+ft.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception {
int i = 0;
for(;i<100;i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
}
- 通过 Callable创建线程____第二种方法
package CreateRunnable3;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestCallable {
public static void main(String[] args)
throws InterruptedException, ExecutionException {
//创建2个线程
ExecutorService ser = Executors.newFixedThreadPool(2);
Race tortoise = new Race("千年王八",1000);
Race rabbit = new Race("小兔子",500);
//获取值
Future result1 = ser.submit(tortoise);
Future result2 = ser.submit(rabbit);
Thread.sleep(1000);//2秒
tortoise.setFlag(false);//停止线程体循环
rabbit.setFlag(false);
int num1 = result1.get();
int num2 = result2.get();
System.out.println("乌龟" + num1);
System.out.println("兔子" + num2);
//停止服务
ser.shutdown();
}
}
class Race implements Callable{
private String name;
private long time;//延时时间
private boolean flag = true;
private int step;//步
public Race(){
}
public Race(String name,long time){
super();
this.name = name;
}
@Override
public Integer call() throws Exception {
while(flag){
Thread.sleep(time);//延时
step++;
}
return step;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public int getStep() {
return step;
}
public void setStep(int step) {
this.step = step;
}
}
创建线程的三种方式的对比
- 采用实现 Runnable、Callable 接口的方式创见多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
- 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
线程的几个主要概念
在多线程编程时,你需要了解以下几个概念:
1); 线程同步
2); 线程间通信
3); 线程死锁
4); [线程控制:挂起、停止和恢复]
Thread 方法
序号 | 方法 | 描述 |
---|---|---|
1 | public void start() | 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 |
2 | public void run() | 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。 |
3 | public final void setName(String name) | 改变线程名称,使之与参数 name 相同。 |
4 | public final void setPriority(int priority) | 更改线程的优先级。 |
5 | public final void setDaemon(boolean on) | 将该线程标记为守护线程或用户线程。 |
6 | public final void join(long millisec) | 等待该线程终止的时间最长为 millis 毫秒。 |
7 | public void interrupt() | 中断线程。 |
8 | public final boolean isAlive() | 测试线程是否处于活动状态。 |
上述方法是被Thread对象调用的。
下面的方法是Thread类的静态方法。
序号 | 方法 | 描述 |
---|---|---|
1 | public static void yield() | 暂停当前正在执行的线程对象,并执行其他线程。 |
2 | public static void sleep(long millisec) | 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
3 | public static boolean holdsLock(Object x) | 当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。 |
4 | public static Thread currentThread() | 返回对当前正在执行的线程对象的引用。 |
5 | public static void dumpStack() | 将当前线程的堆栈跟踪打印至标准错误流。 |
setPriority()
package Priority;
/*
* 线程的优先级
*/
public class TestPriority {
public static void main(String[] args) {
Thread t1 = new Thread(new T1());
Thread t2 = new Thread(new T2());
//把t1的优先级提高3;默认为5,[1,10]
t1.setPriority(Thread.NORM_PRIORITY + 3);
//获取t1的优先级,此处为8
//System.out.println(t1.getPriority());
t1.start();
t2.start();
}
}
class T1 implements Runnable{
public void run(){
for(int i=0;i<20;i++){
System.out.println("T1-"+i);
}
}
}
class T2 implements Runnable{
public void run(){
for(int i=0;i<20;i++){
System.out.println("T2-------------"+i);
}
}
}
线程名称
1,在Thread类中可以通过getName()方法取得线程名称,通过setName()设置线程名称。
2,线程的名称一般在启动线程前设置,但也允许为运行的线程设置名称,允许两个Thread对象有相同名称,但是应该避免。
3,如果程序没有为线程指定名称,系统会自动为线程设置名称。
class MyThread implements Runnable{ // 实现Runnable接口
public void run(){ // 覆写run()方法
for(int i=0;i<3;i++){
//currentThread(),获取当前线程。
System.out.println(Thread.currentThread().getName()
+ "运行,i = " + i) ; // 取得当前线程的名字
}
}
};
public class ThreadNameDemo{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 实例化Runnable子类对象
new Thread(mt).start() ; // 系统自动设置线程名称
new Thread(mt,"线程-A").start() ; // 手工设置线程名称
new Thread(mt,"线程-B").start() ; // 手工设置线程名称
new Thread(mt).start() ; // 系统自动设置线程名称
new Thread(mt).start() ; // 系统自动设置线程名称
}
};
当前线程:CurrentThread()
程序可以通过currentThread()方法取得当前正在运行的线程对象,
class MyThread implements Runnable{ // 实现Runnable接口
public void run(){ // 覆写run()方法
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName()
+ "运行,i = " + i) ; // 取得当前线程的名字
}
}
};
public class CurrentThreadDemo{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 实例化Runnable子类对象
new Thread(mt,"线程").start() ; // 启动线程
mt.run() ; // 直接调用run()方法
}
};
此时发现,程序中由主方法直接通过线程对象调用里面的run()方法,所有此时的结果包含一个"main",此线程就是由“mt.run()”产生的,因为调用此语句是由主方法完成的。
也就是说,主方法本身也是一个线程---主线程。
问题:既然主方法都是以线程的形式出现,那么JAVA启动时候运行了多少线程?
回答:至少启动了两个。
从之前学习的情况来看,每当JAVA执行,都会启动一个JVM,每一个JVM都是在操作系统中启动一个线程。
JAVA本身有垃圾回收机制,所以至少启动了两个线程:主线程,GC。
判断线程是否在执行:isAlive
class MyThread implements Runnable{ // 实现Runnable接口
public void run(){ // 覆写run()方法
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName()
+ "运行,i = " + i) ; // 取得当前线程的名字
}
}
};
public class ThreadAliveDemo{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 实例化Runnable子类对象
Thread t = new Thread(mt,"线程"); // 实例化Thread对象
System.out.println("线程开始执行之前 --> " + t.isAlive()) ; // 判断是否启动
t.start() ; // 启动线程
System.out.println("线程开始执行之后 --> " + t.isAlive()) ; // 判断是否启动
for(int i=0;i<3;i++){
System.out.println(" main运行 --> " + i) ;
}
// 以下的输出结果不确定
System.out.println("代码执行之后 --> " + t.isAlive()) ; // 判断是否启动
}
};
线程强制运行:join()
可以通过join()方法使得一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等待此线程完成之后,才可以继续运行。
package Thread1;
class MyThread implements Runnable{ // 实现Runnable接口
public void run(){ // 覆写run()方法
for(int i=0;i<50;i++){
System.out.println(Thread.currentThread().getName()
+ "运行,i = " + i) ; // 取得当前线程的名字
}
}
};
public class demo1{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 实例化Runnable子类对象
Thread t = new Thread(mt,"线程"); // 实例化Thread对象
t.start() ; // 启动线程
for(int i=0;i<50;i++){
if(i>10){
try{
t.join() ; // 线程强制运行
}catch(InterruptedException e){}
}
System.out.println("Main线程运行 --> " + i) ;
}
}
};
线程的休眠
在线程中允许一个线程进行暂时的休眠,直接使用Thread.sleep()方法即可。
sleep定义格式:
public static void sleep(long milis,int nanos)
throws InterruptedException
首先,static,说明可以由Thread类名称调用,其次throws表示如果有异常要在调用此方法处处理异常。
所以sleep()方法要有InterruptedException 异常处理,而且sleep()调用方法通常为Thread.sleep(500) ;形式。
例子:
package Thread1;
class MyThread implements Runnable{ // 实现Runnable接口
public void run(){ // 覆写run()方法
for(int i=0;i<50;i++){
try{
Thread.sleep(500) ; // 线程休眠
}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()
+ "运行,i = " + i) ; // 取得当前线程的名字
}
}
};
public class demo1{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 实例化Runnable子类对象
Thread t = new Thread(mt,"线程"); // 实例化Thread对象
t.start() ; // 启动线程
}
};
线程的中断
一个线程可以被另一个线程中断其操作的状态,使用 interrupt()方法完成。
package Thread1;
class MyThread implements Runnable{ // 实现Runnable接口
public void run(){ // 覆写run()方法
System.out.println("1、进入run()方法") ;
try{
Thread.sleep(10000) ; // 线程休眠10秒
System.out.println("2、已经完成了休眠") ;
}catch(InterruptedException e){
System.out.println("3、休眠被终止") ;
}
System.out.println("4、run()方法正常结束") ;
}
};
public class demo1{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 实例化Runnable子类对象
Thread t = new Thread(mt,"线程"); // 实例化Thread对象
t.start() ; // 启动线程
try{
Thread.sleep(2000) ; // 线程休眠2秒
}catch(InterruptedException e){
System.out.println("3、休眠被终止") ;
}
t.interrupt() ; // 中断线程执行
}
};
线程的中断
一个线程可以被另一个线程中断其操作的状态,使用 interrupt()方法完成。
package Thread1;
class MyThread implements Runnable{ // 实现Runnable接口
public void run(){ // 覆写run()方法
System.out.println("1、进入run()方法") ;
try{
Thread.sleep(10000) ; // 线程休眠10秒
System.out.println("2、已经完成了休眠") ;
}catch(InterruptedException e){
System.out.println("3、休眠被终止") ;
}
System.out.println("4、run()方法正常结束") ;
}
};
public class demo1{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 实例化Runnable子类对象
Thread t = new Thread(mt,"线程"); // 实例化Thread对象
t.start() ; // 启动线程
try{
Thread.sleep(2000) ; // 线程休眠2秒
}catch(InterruptedException e){
System.out.println("3、休眠被终止") ;
}
t.interrupt() ; // 中断线程执行
}
};
会看到,在1到3的时候会因为线程休眠2秒而卡顿了一下。
但是,既然线程中断了,那么4,这句话不应该打出来的,因此要在3,线程被终止处添加一句话rutrun,表示返回调用处。
package Thread1;
class MyThread implements Runnable{ // 实现Runnable接口
public void run(){ // 覆写run()方法
System.out.println("1、进入run()方法") ;
try{
Thread.sleep(10000) ; // 线程休眠10秒
System.out.println("2、已经完成了休眠") ;
}catch(InterruptedException e){
System.out.println("3、休眠被终止") ;
return ; // 返回调用处
}
System.out.println("4、run()方法正常结束") ;
}
};
public class demo1{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 实例化Runnable子类对象
Thread t = new Thread(mt,"线程"); // 实例化Thread对象
t.start() ; // 启动线程
try{
Thread.sleep(2000) ; // 线程休眠2秒
}catch(InterruptedException e){
System.out.println("3、休眠被终止") ;
}
t.interrupt() ; // 中断线程执行
}
};
后台线程
在Java中,只要一个线程没有执行完(一个线程在运行),则整个Java的进程不会消失,所以此时可以设置一个后台线程,这样即使java线程结束了,则后台线程
依旧会继续执行。要想实现这个操作,要使用setDaemon()方法完成。
class MyThread implements Runnable{ // 实现Runnable接口
public void run(){ // 覆写run()方法
int i=0;
while(true){ //设置死循环,这样来实现线程不断运行,设置后台运行。
System.out.println(Thread.currentThread().getName() + "在运行。"+i) ;
}
}
};
public class ThreadDaemonDemo{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 实例化Runnable子类对象
Thread t = new Thread(mt,"线程"); // 实例化Thread对象
t.setDaemon(true) ; // 此线程在后台运行
t.start() ; // 启动线程
}
};
线程的礼让
yield()方法实现线程的礼让。
package Thread1;
class MyThread implements Runnable{ // 实现Runnable接口
public void run(){ // 覆写run()方法
for(int i=0;i<5;i++){
try{
Thread.sleep(500) ; //休眠一下
}catch(Exception e){}
System.out.println(Thread.currentThread().getName()
+ "运行,i = " + i) ; // 取得当前线程的名字
if(i==2){
System.out.print("线程礼让:") ;
Thread.currentThread().yield() ; // 首先获取当前线程,然后线程礼让
}
}
}
};
public class demo1{
public static void main(String args[]){
MyThread my = new MyThread() ; // 实例化MyThread对象
Thread t1 = new Thread(my,"线程A") ;
Thread t2 = new Thread(my,"线程B") ;
t1.start() ;
t2.start() ;
}
};
多线程的使用
有效利用多线程的关键是理解程序是并发执行而不是串行执行的。例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程。
通过对多线程的使用,可以编写出非常高效的程序。不过请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。
请记住,上下文的切换开销也很重要,如果你创建了太多的线程,CPU 花费在上下文的切换的时间将多于执行程序的时间!