一、多线程的概述
进程:是一个正在执行中的程序。
每个进程执行都至少有一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元。
JVM启动的时候会有一个进程java.exe。该进程中至少一个线程负现java程序的执行,
而且这个线程运行的代码在于main方法中,该线程称之为主线程。
扩展:其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回机制的线程。
二、创建线程-继承Thread类
如何在自定义的代码中,自定义一个线程呢?
线程的创建可通过调用操作系统进行创建。java已经提供了对这类事物的描述,就是Thread类。
创建线程的第一种方式:继承Thread类
1、定义类继承Thread
2、复写Thread类中的run方法
3、调用线程的start方法,该方法两个作用:启动线程,调run方法
class OneThread extends Thread
{
public void run()
{
for(int i = 0;i <60;i++)
{
System.out.println("i = " + i);
}
}
}
public class ThreadDemo {
public static void main(String[] args)
{
OneThread oneThread = new OneThread();//创建一个线程
oneThread.start();//使该线程开始执行;java虚拟机调用该线程的run方法
for(int x = 0;x <60;x++)
{
System.out.println("x = " + x);
}
}
}
上述程序中,oneThread.stat();代码执行后oneThread线程开始执行。这时,上述程序
就有两个线程在同时执行,主线程main和oneThread。两个线程在抢占cpu的执行权,
执行顺序也是随机。每一次运行结果无法确定的。
三、创建线程-run和start特点
run方法是用于储存线程要运行的代码。
start方法启动已创建的线程,并执行run方法
注意:直接调用run方法,程序不会启动相应的线程。下例代码只有main线程在执
行,执行结果,是run方法执行完毕后,再执行main方法中的for循环
OneThread oneThread = new OneThread();//创建一个线程
oneThread.run(); //对象调用run方法,线程未启动
for(int x = 0;x <60;x++)
{
System.out.println("x = " + x);
}
四、线程的状态
线程都会经历从被创建到消亡的过程。线程从被创建后,在各个状态中的转换如下图所示:
五、获取线程的对象及名称
java中的线程都有自己的默认名称,主线程名称是main,其它线程的默名称是
Thread-编号 该编号从0开始。当然也可以自行设置线程的名称
class OneThread extends Thread
{
OneThread()
{
}
//通过构造方法设置线程名称
OneThread(String name)
{
super(name);
}
public void run()
{
for(int i = 0;i <60;i++)
{
/*Thread.currentThread(),获取当前线程寻象的引用
* getName(),获取当前线程的名称
*/
System.out.println(Thread.currentThread().getName() +
" running " + "i = " + i);
}
}
}
public class ThreadDemo {
public static void main(String[] args)
{
OneThread oneThread = new OneThread();//创建一个线程,线程默认名称为Thread-0
OneThread twoThread = new OneThread("线程二");//创建一个线程,并设置线程名称
oneThread.start();//使该线程开始执行;java虚拟机调用该线程的run方法
twoThread.start();
for(int x = 0;x <60;x++)
{
//主线程的名称默认为main
System.out.println(Thread.currentThread().getName() + " running "+
"x = " + x);
}
}
}
六、售票的例子
下例程序是售卖票程序,可多个窗口同时卖。通过继承Thread类实现多线程的方式实现
/*
* 需求:售卖票,可多个窗口同时卖。
*/
class Tick extends Thread
{ //共享这100张票,必须设置成static
private static int tick = 100;
public void run()
{
while(tick > 0)
{
System.out.println(Thread.currentThread().getName() + " sale " +tick--);
}
}
}
public class TickDome {
public static void main(String[] args )
{ //四个窗口同时卖票,创建四个线程
Thread t1 = new Tick();
Thread t2 = new Tick();
Thread t3 = new Tick();
Thread t4 = new Tick();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
七、实现Runnable接口
创建线程的第二种方式:实现Runnable接口
步骤:
1、定认类实现Runnable接口
2、覆盖Runnable接口中的run方法,将线程要运行的中的run方法中
3、通过Thread类建立线程对象
4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造方法。
为什么要将Runnable接口的子类对象传递给Thread的构造方法?
因为,自定义的run对象是Runnable接口的子类对象,所以要让线程去
执行指定对象的run方法,就必须明确该run方法所属对象。
实现方式和继承方式有什么不区别呢?
由于javaj是单继承,所以一旦继承了Thread类,就不能再继承其它类。
实现的方式就避免了单继承的局限性,开发中常使用实现方式。
/*
* 售卖票,可多个窗口同时卖的Runable实现方式
*/
class RTick implements Runnable
{ //多个线程共用一个对象无需定认为静态
private int tick = 100;
public void run()
{
while(tick > 0)
{
System.out.println(Thread.currentThread().getName() + " sale " +tick--);
}
}
}
public class RTickDome {
public static void main(String[] args)
{
RTick rt = new RTick();
Thread t1 = new Thread(rt);
Thread t2 = new Thread(rt);
Thread t3 = new Thread(rt);
Thread t4 = new Thread(rt);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
八、多线程的安全问题及同步代码块
当程序是多线程的,那么就有可能产生某一线程代码块运行未完成,便被其它线程打断
的问题,这有可能导致程序运行出错。
出错的一个原因:
当多条语句操作同一个线程共享数据时,一个线程对多条语句只执行了一部,还没执行
完,另一个线程参与进来执行,导致共享数据的错误。
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其它线程不可
以参与执行
java提供了相应的解决方式,就是同步代码块:
- synchronized(对象)
- {
- 需要被同步的代码
- }
synchronized里的对象如同锁,持有锁的线程可以在同步中执行。
没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。
改进原来的售票程序,如下:
<pre name="code" class="java">class RTick implements Runnable
{ //多个线程共用一个对象无需定认为静态
private int tick = 10000;
Object obj = new Object();
public void run()
{
while(true)
{
//这时的obj对象起开关作用,就像一个锁
synchronized (obj) {
if(tick > 0)
{
System.out.println(Thread.currentThread().getName() + " sale " +tick--);
}
else
break;
}
}
}
}
九、同步方法
我们知道了可以通过同步代码块,对方法内的多条语句加同步锁。那么当我们需要
对方法内的所有语句都进行加同步锁时,可以采用另一种更好的书写方式,叫同步
方法。写书方式很简单,只需使用synchronized关键字修饰即可。
/*
* 需求:银行有一个小金库。
* 有两个储户分别存300元,每次存100,存3次
*/
/*
* 为了防止多线程的运行代码被中断,必须给相关代语句加锁。
* 线程语句中操作共享成员变量的语句不可被中断,加同步锁
*/
class Bank
{
private int sum;
//add方法内的所有语句共同操作共享成员变量sum。
//用synchronized关键字修饰方法,add方法为同步方法
public synchronized void add(int n)
{
sum = sum + n;
System.out.println("sum = " + sum);
}
}
class Cus implements Runnable
{
private Bank b = new Bank();
public void run()
{
for(int x = 0; x<3; x++)
{
b.add(100);
}
}
}
public class BankDemo {
public static void main(String[] args)
{
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
十、同步方法的锁是this
同步方法用的是哪一个锁呢?
方法需要被对象调用。方法都有一个所属对象的引用,就是this,同步方法使用的锁就是this
接下来验证一下这个结论。
验证前必须明确同步的前提:1、必须有两个或者两个以上的线程。2、必须是多个线程使用同一个锁。
若前提(2)不满足,锁无效,基于这一点用如下程序验证:
/*
* 售卖票,两个窗口同时卖票,用于验证同步方法的锁是否为this
* 一个卖票程序位于同步代码块中,一个位于同步方法中,只有用
* 同一个锁才能保证程序不出错
*/
class LTick implements Runnable
{ //多个线程共用一个对象无需定义为静态
private int tick = 1000;
boolean flag =true;
// Object obj = new Object();
public void run()
{
if(flag)
{
while(true)
{
synchronized (this) //使用this程序运行正常,表示与同步方法使用的锁也是this
{
if(tick > 0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName() + " sale " +tick--);
}
else
break;
}
}
}
else
while(true)
{
if(tick <= 0)
break;
saleTick();
}
}
synchronized void saleTick()
{
if(tick > 0)
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName() + " saleTick " +tick--);
}
}
public class LockThisDemo {
public static void main(String[] args)
{
LTick rt = new LTick();
Thread t1 = new Thread(rt);
Thread t2 = new Thread(rt);
t1.start();
try{Thread.sleep(10);}catch(Exception e){}
rt.flag = false;
t2.start();
}
}
十一、静态同步方法的锁是Class对象
如果同步方法被静态修饰后,使用的锁是什么呢?
可通过验证,发现是this。因为静态方法中也不可以定义this。
静态的进内存是,内存中没有本类对象,但是一定有该类对应的字节码对象文件——类名.Class
class LTick implements Runnable
{ //定义为静态成员
private static int tick = 1000;
boolean flag =true;
public void run()
{
if(flag)
{
while(true)
{
synchronized (LTick.class) //Class类型的对象
{
if(tick > 0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName() + " sale " +tick--);
}
else
break;
}
}
}
else
while(true)
{
if(tick <= 0)
break;
saleTick();
}
}
static synchronized void saleTick() //静态同步方法
{
if(tick > 0)
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName() + " saleTick " +tick--);
}
}
十一、多线程-单例设计模式-懒汉式
在前面我们个绍过懒汉式的单例设计模式,这个模式存在技术风险。知道了多线程中的
锁,我们就可以来解决这个问题了。因为在getInstance()方法中有多条语句操作生成共
享成员变量(LSingle对象),所以存在被多个线程同时调用时,程序被中断而可能出现
程序运行结果不正确的风险。只需用同步方法即可解决,但是每次调用getInstance()都
要判断锁,会降低性能,因此,我们采用同步代代码块进行解决,见示例代码:
class LSingle
{
private static LSingle s = null;
private LSingle(){};
public static LSingle getInstance() {
if(s == null)
{
synchronized(LSingle.class)
{
if(s==null)
s = new LSingle();
}
}
return s;
}
}
十二、多线程-死锁
什么是死锁呢?考虑一下这样的情景,有两个人要吃饭,桌上有一双筷子各自拿了一根
筷子,互不让,这样两人都无法吃饭。类似的程序中也有可能出现这样一种情况,有两
个线程,每个线程代码都同时需要两个锁,才能正常运行。各自拿了一个锁,导致两线
程都无法正常运行。
//测试死锁程序
class TestLock implements Runnable
{
boolean flag = false;
TestLock(boolean flag)
{
this.flag = flag;
}
public void run()
{
if(this.flag == true)
{ //同步嵌套,可能会死锁
synchronized(MyLock.la)
{
System.out.println("if locka");
synchronized(MyLock.lb)
{
System.out.println("if lockb");
}
}
}
else
{ //同步嵌套,可能会死锁
synchronized(MyLock.lb)
{
System.out.println("else lockb");
synchronized(MyLock.la)
{
System.out.println("else locka");
}
}
}
}
}
class MyLock
{
//两个同步用的锁
static Object la = new Object();
static Object lb = new Object();
}
public class TestLockDemo {
public static void main(String[] args)
{
Thread t1 =new Thread(new TestLock(true));
Thread t2 =new Thread(new TestLock(false));
t1.start();
t2.start();
}
}
十三、多线程的通信-wait()、notify()、notifyAll()
一个程序中的多个线程可能需要对同一资源进行操作,且不同的线程的功能不同,这样
线程之间就需要协作,协作就需要进行通信。在同步方法和语句中常见的通信操作有定
义在Object中的wait()、notify()、notifyAll()。注意,wait()方法的执行会释放synchronized
中的锁。下面的例子演示的这种用法:
/*
* 线程通信。Input线程与Output线程操作同一个资源
* 存一个信息就打印一个信息
*/
class Res
{
String name;
String sex;
boolean flag = false;
}
//往资源里面存入信息
class Input implements Runnable
{
private Res r;
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
synchronized(Res.class)
{
if(r.flag)
{
try
{
Res.class.wait(); //执行wait()会释放锁
}
catch(Exception e)
{
}
}
if(x == 0)
{
r.name = "mike";
r.sex = "man";
}
else
{
r.name = "丽丽";
r.sex = "女女女女";
}
x = (x +1) % 2;
r.flag = true;
Res.class.notify();
}
}
}
}
//打印资源里面信息
class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while(true)
synchronized(Res.class)
{
if(!r.flag)
{
try
{
Res.class.wait();
}
catch(Exception e)
{
}
System.out.println(r.name +"----" + r.sex);
}
r.flag = false;
Res.class.notify();
}
}
}
public class InOutDome {
public static void main(String[] args)
{
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
输出如下:
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
可对上述的代码进行优化:
/*
* 优化代码
* 线程通信。Input线程与Output线程操作同一个资源
* 存一个信息就打印一个信息
*/
class Res2
{
private String name;
private String sex;
private boolean flag = false;
synchronized void set(String name,String sex)
{
if(flag)
{
try
{
this.wait();
}
catch(Exception e)
{
}
}
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
synchronized void out()
{
try
{
if(!flag)
{
this.wait();
}
}
catch(Exception e)
{
}
System.out.println(this.name +"----" + this.sex);
this.flag = false;
this.notify();
}
}
//往资源里面存入信息
class Input2 implements Runnable
{
private Res2 r;
Input2(Res2 r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
if(x == 0)
{
r.set("mike","man");
}
else
{
r.set("丽丽---------","女女女女");
}
x = (x +1) % 2;
}
}
}
//打印资源里面信息
class Output2 implements Runnable
{
private Res2 r;
Output2(Res2 r)
{
this.r = r;
}
public void run()
{
while(true)
r.out();
}
}
public class InOutDome2 {
public static void main(String[] args)
{
Res2 r = new Res2();
new Thread(new Input2(r)).start();
new Thread(new Output2(r)).start();
}
}
在实际开发中,有一种与上述程序类似的模式,叫生产者消费者模式。生产一个
消费模式,多个线程生产,多个线程消费
/*
* 生产者、消费者。两个线程生产,两个线程消费
*/
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
synchronized void set(String name)
{
/*之所以用while,不用if是因为某一线程执行了wait()后,被其它
* 线程唤醒后,会从wait()后开始执行,程序就没有判断flag,可
* 能引起错误,用while保证每次执行都会判断flag
*/
while(flag)
{
try
{
wait(); //省略了this
}
catch(Exception e)
{
}
}
this.name = name + count++;
System.out.println(Thread.currentThread().getName() + "-----" + "生产者" +this.name);
flag = true;
notifyAll(); //唤醒全部线程
}
synchronized void out()
{
while(!flag)
{
try
{
wait(); //省略了this
}
catch(Exception e)
{
}
}
System.out.println(Thread.currentThread().getName() + "----------------" + "消费者"+name);
flag = false;
notifyAll();
}
}
class Producer implements Runnable
{
private Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("商品");
}
}
}
class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
}
public class ProducerConsumerDemo
{
public static void main(String[] args)
{
Resource r = new Resource();
Producer p = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 =new Thread(p);
Thread t2 =new Thread(p);
Thread t3 =new Thread(con);
Thread t4 =new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
十四、多线程的通信-Lock-Condition
在JDK1.5引进了Lock-Condition。Lock接口替代synchronized方法和语句的使用,
Condition接口替代了Object监初视器方法的使用。一个Lock支持邦定多个Condition
对象使用Condition实现了对特定的线程进行操作
/*
* 该程序是生产者、消费者的Lock-Condition版。
* 该示例实现了本方线程对对方线程的唤醒。
*/
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Lock;
class LResource
{
private String name;
private int count = 1;
private boolean flag = false;
private Lock lock = new ReentrantLock(); //创建一个锁
private Condition conditionPro = lock.newCondition();//邦定到锁的Condition对象
private Condition conditionCon = lock.newCondition();
void set(String name) throws InterruptedException
{
lock.lock();
try
{
while(flag)
{
conditionPro.await(); //生产者对应线程等待
}
this.name = name + count++;
System.out.println(Thread.currentThread().getName() + "-----" + "生产者" +this.name);
flag = true;
conditionCon.signal();; //唤醒消费者对应线程
}
finally
{
lock.unlock();
}
}
void out() throws InterruptedException
{
lock.lock();
try
{
while(!flag)
{
conditionCon.await();//消费者对应线程等待
}
System.out.println(Thread.currentThread().getName() + "----------------" + "消费者"+name);
flag = false;
conditionPro.signal(); //唤醒生产者对应线程
}
finally
{
lock.unlock();
}
}
}
class LProducer implements Runnable
{
private LResource r;
LProducer(LResource r)
{
this.r = r;
}
public void run()
{
while(true)
{
try
{
r.set("商品");
}
catch(Exception e)
{
}
}
}
}
class LConsumer implements Runnable
{
private LResource r;
LConsumer(LResource r)
{
this.r = r;
}
public void run()
{
while(true)
{
try
{
r.out();
}
catch(Exception e)
{
}
}
}
}
public class LProducerConsumerDemo
{
public static void main(String[] args)
{
LResource r = new LResource();
LProducer p = new LProducer(r);
LConsumer con = new LConsumer(r);
Thread t1 =new Thread(p);
Thread t2 =new Thread(p);
Thread t3 =new Thread(con);
Thread t4 =new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
十四、停止线程
Threadable类中有stop方法,但以过时。
如何停止线程?只有一种方式,run方法结束。
开启多线程运行,运行代码通常是循环结构。只要控制信循环,就可以让run方法结束,
也就线程结束。
//正常情况下停止线程
class StopThread implements Runnable
{
private boolean flag = true;
public void run()
{
while(flag)
{
System.out.println(Thread.currentThread().getName() + "----------run");
}
}
void changeFlag()
{
flag = false;
}
}
public class StopThreadDemo {
public static void main(String[] args)
{
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int i = 0;
while(true)
{
if(i >=60)
{
st.changeFlag();
break;
}
System.out.println(Thread.currentThread().getName() + "----main" + i++);
}
}
}
特殊情况:
当线程处于冻结状态,程序不会读取到标记,那么线程不会结束。那么可以使用Thread类
提供的interrupt()方法,强制线程恢复到运行状态中来,这样就可以操作标记让线程结束。
//停止处于冻结状态的线程
class StopThread2 implements Runnable
{
private boolean flag = true;
public synchronized void run()
{
while(flag)
{
try
{
wait();
}
//被interrupt方法强制清除冻结状态,wait()会抛出异常InterruptedException
catch(InterruptedException e)
{
System.out.println(Thread.currentThread().getName() + "---Exception");
flag = false;
}
System.out.println(Thread.currentThread().getName() + "----------run");
}
}
void changeFlag()
{
flag = false;
}
}
public class StopThreadDemo2 {
public static void main(String[] args)
{
StopThread2 st = new StopThread2();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int i = 0;
while(true)
{
if(i >=60)
{
//st.changeFlag();
t1.interrupt();//强制清除t1线程的中断状态
t2.interrupt();//强制清除t2线程的中断状态
break;
}
System.out.println(Thread.currentThread().getName() + "----main" + i++);
}
System.out.println("over");
}
}
十五、守护线程
线程可分为用护线程和守护线程,当程序中只能守护线程时,jvm退出,即守护线程
结束。在线程的启动前可调用Thread的setDaemon()方法将线程标记为守护线程或
用户线程。
//主线程停止,守护线程随之停止
class StopThread implements Runnable
{
//private boolean flag = true;
public void run()
{
while(true)
{
System.out.println(Thread.currentThread().getName() + "----------run");
}
}
// void changeFlag()
// {
// flag = false;
// }
}
public class StopThreadDemo {
public static void main(String[] args)
{
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
//标记为守护线程
t1.setDaemon(true);
t2.setDaemon(true);
t1.start();
t2.start();
int i = 0;
while(true)
{
if(i >=60)
{
//st.changeFlag();
break;
}
System.out.println(Thread.currentThread().getName() + "----main" + i++);
}
System.out.println("over");
}
}
主线程停止,守护线程随之停止
main----main53
main----main54
main----main55
main----main56
main----main57
main----main58
main----main59
over //主线程在这里停止了
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-0----------run //守护线程在这里停止了
十六、join方法
join方法:
当A线程执行到了B线程join方法时,A就会等待,等B线程执行完,A才会执行。、
join可以用来临时加入到线程执行
class JoinThread implements Runnable
{
public void run()
{
for(int i = 0;i < 70;i++)
{
System.out.println(Thread.currentThread().getName() + "-run");
}
}
}
public class JoinThreadDemo {
public static void main(String[] args) throws InterruptedException
{
JoinThread jt = new JoinThread();
Thread t1 = new Thread(jt);
Thread t2 = new Thread(jt);
t1.start();
//t1.join(); 主线程停止,等t1线程执行完主线程才往下执行
t2.start();
t1.join();// 主线程停止,等t1线程执行完主线程才往下执行,t1和t2同时执行
for(int i = 0;i < 70;i++)
{
System.out.println(Thread.currentThread().getName() + "-run");
}
System.out.println("over");
}
}
十七、优先级与yield方法
线程有优先级从1~10,默认是情况下是第5级。优先级越大抢到执行权的频率就越高。
优先级的大小可通过Thread类的setPriority方法设定优先级。
有时为了使程序的线程能尽可能的平均、交替的执行,可使用yield方法当前线程暂停一
下,将执行权让给其它线程。
class Yield implements Runnable
{
public void run()
{
for(int i = 1;i <70;i++)
{ //toString返回线程名称、优先级、线程组
System.out.println(Thread.currentThread().toString() + i);
Thread.yield(); //暂停一下当前线程
}
}
}
class Priority implements Runnable
{
public void run()
{
for(int i = 1;i <70;i++)
{
System.out.println(Thread.currentThread().toString() + i);
}
}
}
public class PriorityYieldDemo {
public static void main(String[] args)
{
Yield y = new Yield();
Priority p = new Priority();
Thread t1 = new Thread(y);
Thread t2 =new Thread(y);
Thread t3 = new Thread(p);
t1.start();
t2.start();
t3.setPriority(Thread.MAX_PRIORITY);//设置线程t3为最高优先级
t3.start();
}
}