标签:
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一、进程、线程、多进程的概念
1、进程和线程
进程:正在进行中的程序。其实进程就是一个应用程序运行时的内存分配空间。
线程:其实就是进程中一个程序执行控制单元,一条执行路径。进程负责的是应用程序的空间的标示。线程负责的是应用程序的执行顺序。
一个进程至少有一个线程在运行,当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序,每个线程在栈区中都有自己的执行空间,自己的方法区、自己的变量。
2、java虚拟机就是多线程程序
jvm在启动的时,首先有一个主线程,负责程序的执行,调用的是main函数。主线程执行的代码都在main方法中。
当产生垃圾时,收垃圾的动作,是不需要主线程来完成,因为这样,会出现主线程中的代码执行会停止,会去运行垃圾回收器代码,效率较低,所以由单独一个线程来负责垃圾回收。
3、多线程的好坏之处
多线程的好处:解决了多部分代码同时运行的问题。
多线程的弊端:线程太多,会导致效率的降低。
其实,多个应用程序同时执行都是CPU在做着快速的切换完成的。这个切换是随机的。哪个线程抢到了cpu的执行权,哪个线程就执行。CPU的切换是需要花费时间的,从而导致了效率的降低。
创建线程的目的就是为了开启一条执行路径,去运行指定的代码和其他代码实现同时运行,而运行的指定代码就是这个执行路径的任务。
二、创建线程的方式
1、获取当前线程名称
Thread.currentThread().getName();
线程的名称是由:Thread-编号定义的。编号从0开始。
线程要运行的代码都统一存放在了run方法中。
2、创建线程的方式
(1)、第一种方式:继承Thread类,由子类复写run方法。
1. 定义一个类继承Thread类。
2. 覆盖Thread类中的run方法。
3. 直接创建Thread的子类对象创建线程。
4. 调用start方法开启线程并调用线程的任务run方法执行。
run方法就是封装自定义线程运行任务的函数,run方法中定义的就是线程要运行的任务代码。记住:把需要开启多线程的运行代码都写到run方法中。
代码演示:
1 //继承Thread类,复写run方法 2 class Demo extends Thread 3 { 4 public void run(){//run方法内不能抛异常,只能try catch。因为该方法是复写Thread类中的run方法。Thread类中的run方法没有抛异常 5 for (int x=0;x<70 ;x++ ) 6 { 7 System.out.println(Thread.currentThread().getName()+"....."+x); 8 } 9 } 10 } 11 class ThreadDemo 12 { 13 public static void main(String[] args) //开启了两个线程:Demo和main。两个线程交替运行 14 { 15 new Demo().start();//创建子类对象,并开启线程,调用run方法 16 for (int x=0;x<70 ;x++ ) 17 { 18 System.out.println(Thread.currentThread().getName()+":::"+x);//mian函数的线程名称就是:main 19 } 20 } 21 }
自定义线程名称的方法
1 class Demo extends Thread 2 { 3 private String name; 4 Demo(String name){ 5 super(name); 6 } 7 public void run(){ 8 System.out.println(Thread.currentThread().getName()); 9 } 10 } 11 class ThreadDemo 12 { 13 publici static void main(Stirng[] args){ 14 new Demo("线程一").start(); 15 new Demo("线程二").start(); 16 } 17 }
(2)、创建线程的第二种方式:实现Runnable接口,复写run方法。
1.定义类实现Runnable接口
2.覆盖接口中的run方法(用于封装线程要运行的代码)
3.通过Thread类创建线程对象
4.将实现了Runnable接口的子类对象作为实际参数传递给Thread类中的构造函数。
为什么要传递呢?线程的任务都封装在Runnable接口子类对象的run方法中,所以要在线程对象创建时就必须明确要运行的任务。
5.调用Thread对象的start方法。开启线程,并运行Runnable接口子类中的run方法。
为什么要有Runnable接口的出现?
1.通过继承Thread类的方式,可以完成多线程的建立。但是这种方式有一个局限性,如果一个类已经有了自己的父类,就不可以继承Thread类,因为java单继承的局限性。
可是该类中的还有部分代码需要被多个线程同时执行。这时怎么办呢?
只有对该类进行额外的功能扩展,java就提供了一个接口Runnable。这个接口中定义了run方法,其实run方法的定义就是为了存储多线程要运行的代码。
所以,通常创建线程都用第二种方式。因为实现Runnable接口可以避免单继承的局限性。
2.其实是将不同类中需要被多线程执行的代码进行抽取。将多线程要运行的代码的位置单独定义到接口中。为其他类进行功能扩展提供了前提。所以Thread类在描述线程时,内部定义的run方法,也来自于Runnable接口。
实现Runnable接口可以避免单继承的局限性。而且,继承Thread,是可以对Thread类中的方法,进行子类复写的。但是不需要做这个复写动作的话,只为定义线程代码存放位置,实现Runnable接口更方便一些。所以Runnable接口将线程要执行的任务封装成了对象。
代码演示:
1 //实现Runnable,复写run方法 2 class Demo implements Runnable 3 { 4 public void run(){ 5 for (int x=0;x<60 ;x++ ) 6 { 7 System.out.println(Thread.currentThread().getName()+".."+x); 8 } 9 } 10 } 11 class ThreadDemo 12 { 13 public static void main(String[] args) 14 { 15 new Thread(new Demo()).start(); 16 for (int x=0;x<60 ; x++) 17 { 18 System.out.println(Thread.currentThread().getName()+":::::"+x); 19 } 20 } 21 }
(3)、线程状态
被创建:start()
运行:具备了执行资格,同时也具备执行权
临时阻塞状态:线程具备cpu的执行资格,但是没有cpu的执行权
冻结:sleep(time),wait()--notify(),失去执行资格和执行权。sleep方法时间到或者调用notify()方法时,获得执行资格,变为临时状态
消亡:stop()方法,或者run()方法结束
三、线程安全问题
1、多线程安全问题的原因
通过图解:发现一个线程在执行多条语句时,并运算同一个数据时,在执行过程中,其他线程参与进来,并操作了这个数据。导致到了错误数据的产生。
涉及到两个因素:
1.多个线程在操作共享数据。
2.有多条语句对共享数据进行运算。
原因:这多条语句,在某一个时刻被一个线程执行时,还没有执行完,就被其他线程执行了。
2、线程安全问题的解决方案
解决安全问题的原理:
只要将操作共享数据的语句在某一时段让一个线程执行完,在执行过程中,其他线程不能进来执行就可以解决这个问题。必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
解决同步的方式:
(1)、同步代码块的格式:
synchronized(对象){// 任意对象都可以。这个对象就是锁。
需要被同步的代码;
}
同步的好处:解决了线程的安全问题。
同步的弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
同步的前提:必须有多个线程并使用同一个锁。
需求:模拟4个线程同时卖100张票。
1 //加上同步代码块后 2 class Ticket implements Runnable 3 { 4 private int ticket=100; 5 private Object obj=new Object(); 6 public void run(){ 7 while (true) 8 { 9 synchronized(obj){//加上同步代码块后,obj对象相当于一把锁,一个线程进去后,其他线程无法进去,只有当这个线程执行完,跳出同步后,另一个才能进去 10 if (ticket>0)//一个线程进同步有两个隐式操作,刚进同步后:上锁,跳出同步后:释放锁 11 { 12 try{Thread.sleep(20);}catch(Exception e){}//让线程停止20毫秒,这时候出现了线程等于0、-1、-2的情况 13 System.out.println(Thread.currentThread().getName()+"..."+ticket--);//出现问题的原因是:线程停止了20毫秒后,继续运行的时候没有判断if的条件。 14 } 15 } 16 } 17 18 } 19 } 20 class TicketDemo 21 { 22 public static void main(String[] args) 23 { 24 Ticket t=new Ticket(); 25 new Thread(t).start(); 26 new Thread(t).start(); 27 new Thread(t).start(); 28 new Thread(t).start(); 29 } 30 }
需求:储户,两个,每个都到银行存钱,每次存100,共存三次。
1 class Bank 2 { 3 private Object obj=new Object(); 4 private int sum; 5 public void add(int num){ 6 synchronized(obj){ 7 sum=sum+num; 8 try{Thread.sleep(10);}catch(Exception e){} 9 System.out.println("sum="+sum); 10 } 11 } 12 } 13 class Person implements Runnable 14 { 15 private Bank b=new Bank(); 16 public void run(){ 17 for(int x=0;x<3;x++){ 18 b.add(100); 19 } 20 } 21 } 22 class BankDemo 23 { 24 public static void main(String[] args) 25 { 26 Person p=new Person(); 27 new Thread(p).start(); 28 new Thread(p).start(); 29 } 30 }
(2)、同步函数
同步函数:其实就是将同步关键字定义在函数上,让函数具备了同步性。
上面的代码可以用同步函数代替同步代码块。
1 class Bank 2 { 3 private int sum; 4 public synchronized void add(int num){ 5 sum=sum+num; 6 try{Thread.sleep(10);}catch(Exception e){} 7 System.out.println("sum="+sum); 8 } 9 }
同步函数用的是哪一个锁呢?函数需要被对象调用。那么函数都有一个所属对象引用。就是this。所以同步函数使用的锁是this。
同步函数和同步代码块的区别:
1. 同步函数的锁是固定的this。
2. 同步代码块的锁是任意的对象。
建议使用同步代码块。
关于同步函数用的是this锁,可以通过该程序进行验证。使用两个线程来买票。一个线程在同步代码块中。一个线程在同步函数中。都在执行卖票动作。
1 class Ticket implements Runnable 2 { 3 private int ticket=100; 4 boolean flag; 5 public void run(){ 6 if(flag){ 7 while (true) 8 { 9 synchronized(this){ 10 if(ticket>0){ 11 try{Thread.sleep(10);}catch(Exception e){} 12 System.out.println(Thread.currentThread().getName()+"..obj."+ticket--); 13 } 14 } 15 } 16 } 17 else 18 while(true) 19 show(); 20 } 21 public synchronized void show(){ 22 if(ticket>0){ 23 try{Thread.sleep(10);}catch(Exception e){} 24 System.out.println(Thread.currentThread().getName()+"::this::"+ticket--); 25 } 26 27 } 28 } 29 class ThisLockDemo 30 { 31 public static void main(String[] args) 32 { 33 Ticket t=new Ticket(); 34 new Thread(t).start(); 35 try{Thread.sleep(10);}catch(Exception e){}//让线程一先sleep一会,这时候主线程还获取执行权,继续向下执行 36 t.flag=true;//标记为true,这时候会运行show方法中的代码 37 new Thread(t).start(); 38 } 39 }
上面的代码显示两个线程交替执行而且把100张票卖完了,而且没有出现0号和负数的票,说明两个线程是安全的,同时也说明了同步函数用的锁是this。
(3)、静态同步函数
当同步函数被static修饰时,这时的同步用的是哪个锁呢?
静态函数在加载时所属于类,这时有可能还没有该类产生的对象,但是该类的字节码文件加载进内存就已经被封装成了对象,这个对象就是该类的字节码文件对象。
所以静态加载时,只有一个对象存在,那么静态同步函数就使用的这个对象。
这个对象就是 类名.class。
还是用卖票的程序可以验证静态同步函数的锁是.class。
1 class Ticket implements Runnable 2 { 3 private static int ticket=100; 4 boolean flag; 5 public void run(){ 6 if(flag){ 7 while (true) 8 { 9 synchronized(Ticket.class){ 10 if(ticket>0){ 11 try{Thread.sleep(10);}catch(Exception e){} 12 System.out.println(Thread.currentThread().getName()+"..obj."+ticket--); 13 } 14 } 15 } 16 } 17 else 18 while(true) 19 show(); 20 } 21 public static synchronized void show(){ 22 if(ticket>0){ 23 try{Thread.sleep(10);}catch(Exception e){} 24 System.out.println(Thread.currentThread().getName()+"::this::"+ticket--); 25 } 26 27 } 28 } 29 class ThisLockDemo 30 { 31 public static void main(String[] args) 32 { 33 Ticket t=new Ticket(); 34 new Thread(t).start(); 35 try{Thread.sleep(10);}catch(Exception e){}//让线程一先sleep一会,这时候主线程还获取执行权,继续向下执行 36 t.flag=true;//标记为true,这时候会运行show方法中的代码 37 new Thread(t).start(); 38 } 39 }
在一个类中只有一个同步,可以使用同步函数。如果有多同步,必须使用同步代码块,来确定不同的锁。所以同步代码块相对灵活一些。
四、多线程下的单例设计模式
饿汉式不存在线程安全问题,因为操作的代码只有一句。
1 class Single 2 { 3 private Single(){} 4 private static final Single s=new Single(); 5 public static Single getInstance(){ 6 return s; 7 } 8 }
1 class Single 2 { 3 private Single(){} 4 private static Single s=null; 5 public static Single getInstance(){//如果在函数上加上synchronized就出现了每次都判断锁 6 if(s==null){//双重判断是否为空可以解决低效问题。 7 synchronized(Single.class){ 8 if(s==null){ 9 s=new Single(); 10 } 11 } 12 } 13 return s; 14 } 15 }
五、死锁
1 class DeadLock implements Runnable 2 { 3 private boolean flag; 4 DeadLock(boolean flag){ 5 this.flag=flag; 6 } 7 public void run(){ 8 if(flag){ 9 while (true) 10 { 11 synchronized(MyLock.locka){//同步代码块中嵌套同步代码块 12 System.out.println("if....locka..."); 13 synchronized(MyLock.lockb){ 14 System.out.println("if....lockb..."); 15 } 16 } 17 } 18 } 19 else{ 20 while (true) 21 { 22 synchronized(MyLock.lockb){ 23 System.out.println("else-----lockb--"); 24 synchronized(MyLock.locka){ 25 System.out.println("else-----locka---"); 26 } 27 } 28 } 29 } 30 } 31 } 32 class MyLock 33 { 34 public static MyLock locka=new MyLock(); 35 public static MyLocks lockb=new MyLock(); 36 } 37 class DeadLockDemo 38 { 39 public static void main(String[] args) 40 { 41 new Thread(new DeadLock(true)).start(); 42 new Thread(new DeadLock(false)).start(); 43 44 } 45 }
六、线程间通信问题
线程间通信:思路:多个线程在操作同一个资源,但是操作的动作却不一样。
1.将资源封装成对象。
2.将线程执行的任务(任务其实就是run方法。)也封装成对象。
等待/唤醒机制涉及的方法:
1. wait():让线程处于冻结状态,被wait的线程会被存储到线程池中。
2. notify():唤醒线程池中的一个线程(任何一个都有可能)。
3. notifyAll():唤醒线程池中的所有线程。
这些方法都使用在同步中,因为要对持有监视器(锁)的线程操作。所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义Object类中呢?
因为这些方法在操作同步中线程时,都必须要标识它们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。不可以对不同锁中的线程进行唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
wait和sleep区别?
1.wait可以指定时间也可以不指定。sleep必须指定时间。
2.在同步中时,对CPU的执行权和锁的处理不同。
wait:释放执行权,释放锁。
sleep:释放执行权,不释放锁。
(1)、一个生产者,一个消费者。即: 一个线程负责生产,一个线程负责消费
代码演示:
1 class Resource 2 { 3 private String name; 4 private String sex; 5 private boolean flag; 6 public synchronized void set(String name,String sex){ 7 if(flag)//如果为真,执行下面wait方法,线程处于等待状态,释放了执行权并且放弃了锁。 8 try{this.wait();}catch(Exception e){} 9 //如果标记不为true,那么往里面存数据。 10 this.name=name; 11 this.sex=sex; 12 flag=true; 13 this.notify();//唤醒线程池中第一个等待的线程 14 } 15 public synchronized void out(){ 16 if(!flag) 17 try{this.wait();}catch(Exception e){} 18 System.out.println(name+"...."+sex); 19 flag=false; 20 this.notify(); 21 } 22 } 23 class Input implements Runnable 24 { 25 private Resource r;//为了保证操作的是同一资源,所以把资源对象传参进去 26 Input(Resource r){ 27 this.r=r; 28 } 29 public void run(){ 30 int x=0; 31 while (true) 32 { 33 if(x==0) 34 r.set("mike","man"); 35 else 36 r.set("丽丽","女女女女女女"); 37 x=(x+1)%2;//切换输入内容 38 } 39 } 40 } 41 class Output implements Runnable 42 { 43 private Resource r; 44 Output(Resource r){ 45 this.r=r; 46 } 47 public void run(){ 48 while (true) 49 { 50 r.out(); 51 } 52 } 53 } 54 class ResourceDemo 55 { 56 public static void main(String[] args) 57 { 58 Resource r=new Resource();//创建资源对象 59 new Thread(new Input(r)).start();//开启两个线程 60 new Thread(new Output(r)).start(); 61 } 62 }
(2)、多生产--多消费问题
上面的例子是一个输入一个输出,现在是多个线程执行输入同时多条线程执行输出。即:多个线程操作生产,多个线程操作消费。这是开发中最常见的,希望能够掌握。
1 class Resource 2 { 3 private String name; 4 private int count=1; 5 private boolean flag=false; 6 public synchronized void set(String name){ 7 while(flag)//循环判断标记来防止线程等待被唤醒后往下执行,直接生产覆盖上一个数据。 8 try{this.wait();}catch(Exception e){} 9 this.name=name+"....."+count++; 10 System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name); 11 flag=true; 12 this.notifyAll();//唤醒线程池中的全部线程 13 } 14 public synchronized void out(){ 15 while(!flag) 16 try{this.wait();}catch(Exception e){} 17 System.out.println(Thread.currentThread().getName()+"----消费者-------"+this.name); 18 flag=false; 19 this.notifyAll();//唤醒线程池中的全部线程 20 } 21 } 22 class Producer implements Runnable 23 { 24 private Resource r; 25 Producer(Resource r){ 26 this.r=r; 27 } 28 public void run(){ 29 while (true) 30 { 31 r.set("商品"); 32 } 33 } 34 } 35 class Consumer implements Runnable 36 { 37 private Resource r; 38 Consumer(Resource r){ 39 this.r=r; 40 } 41 public void run(){ 42 while (true) 43 { 44 r.out(); 45 } 46 } 47 } 48 class ProducerConsumerDemo 49 { 50 public static void main(String[] args) 51 { 52 Resource r=new Resource(); 53 new Thread(new Producer(r)).start(); 54 new Thread(new Producer(r)).start(); 55 new Thread(new Consumer(r)).start(); 56 new Thread(new Consumer(r)).start(); 57 58 } 59 }
七、线程间通信-生产者消费者JDK1.5升级版
上面的程序虽然能够解决问题,但是发现每次都唤醒全部线程,这样会导致线程都去抢夺cpu执行权,效率有点低,所以JDK在升级1.5的时候推出了一个接口Lock接口。它的出现就替代了同步代码块或者同步函数,将同步的隐式操作变成显示锁操作。同时更为灵活,可以一个锁上加上多组监视器。。
在之前的版本中使用Object类中wait、notify、notifyAll的方法来完成的,那是因为同步中的锁是任意对象,所以操作时的等待唤醒的方法是都是定义在Object类中。而现在锁是指定对象Lock,所以查找等待唤醒机制方式需要通过Lock接口来完成.而Lock接口中并没有直接操作等待唤醒的方法,而是将这些方法又单独的封装了一个对象中,这个对象就是Condition,将Object中的三个方法进行了单独的封装,并提供了功能一致的方法await()、signal()、signalAll()。所以Condition接口出现替代了Object中的wait、notify、notifyAll方法。将这些监视器方法单独进行了封装,变成Condition监视器对象,可以任意锁进行组合。
Lock接口
1 Lock lock=new ReentrantLock();//创建Lock对象 2 void lock();//获取锁。 3 void unlock();//释放锁,为了防止异常出现,导致锁无法被关闭,所以锁的关闭动作要放在finally中。
4 Condition newCondition();//获取Condition对象
Condition接口
1 void await();//对应于Object中的wait方法 2 void signal();//对应于Object中的notify方法 3 void signalAll();//对应于Object中的notifyAll方法
JDK1.5多生产--多消费问题代码
1 import java.util.concurrent.locks .*; 2 class Resource 3 { 4 private boolean flag; 5 private Lock lock=new ReentrantLock();//创建Lock对象 6 private Condition procondition=lock.newCondition();//创建Condition对象 7 private Condition concondition=lock.newCondition(); 8 private int count=1; 9 private String name; 10 public void set(String name){ 11 lock.lock();//显示的加锁 12 try 13 { 14 while(flag) 15 procondition.await();//await替换了wait; 16 this.name=name+"..."+count++; 17 System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name); 18 flag=true; 19 concondition.signal();//signal替换了notify 20 } 21 catch (Exception e) 22 { 23 System.out.println(e); 24 } 25 finally{ 26 lock.unlock();//释放锁,释放资源的动作一定要放在finally块中 27 } 28 29 } 30 public void out(){ 31 lock.lock(); 32 try 33 { 34 while(!flag) 35 concondition.await(); 36 System.out.println(Thread.currentThread().getName()+"------消费者-----"+this.name); 37 flag=false; 38 procondition.signal(); 39 } 40 catch (Exception e) 41 { 42 System.out.println(e); 43 } 44 finally{ 45 lock.unlock(); 46 } 47 } 48 } 49 class Producer implements Runnable 50 { 51 private Resource r; 52 Producer(Resource r){ 53 this.r=r; 54 } 55 public void run(){ 56 while (true) 57 { 58 r.set("商品"); 59 } 60 } 61 } 62 class Consumer implements Runnable 63 { 64 private Resource r; 65 Consumer(Resource r){ 66 this.r=r; 67 } 68 public void run(){ 69 while (true) 70 { 71 r.out(); 72 } 73 } 74 } 75 class ProducerConsumerDemo2 76 { 77 public static void main(String[] args) 78 { 79 Resource r=new Resource(); 80 new Thread(new Producer(r)).start(); 81 new Thread(new Producer(r)).start(); 82 new Thread(new Consumer(r)).start(); 83 new Thread(new Consumer(r)).start(); 84 } 85 }
八、Thread类中其他方法
1、停止线程
查看API发现线程停止方法stop方法已经过时了,所以我们无法在使用。其实让线程停止的原理就是:run方法结束。
开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。
所以run方法中通常定义循环,指定控制住循环线程即可结束。
特殊情况:当线程处于了冻结状态。就不会读取到标记。那么线程就不会结束。当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。Thread类提供该方法 interrupt(),interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备CPU的执行资格。强制动作会发生InterruptedException,一定要记得处理。
1 class StopThread implements Runnable{ 2 private boolean flag = true; 3 public void run(){ 4 while(flag ){ 5 System. out.println(Thread.currentThread().getName() + "..."); 6 } 7 } 8 public void setFlag(){ 9 flag = false ; 10 } 11 } 12 13 class StopThreadDemo{ 14 public static void main(String[] args){ 15 StopThread st = new StopThread(); 16 new Thread(st).start(); 17 new Thread(st).start(); 18 19 int num = 0; 20 while(true){ 21 if(num++ == 50){ 22 st.setFlag(); 23 break; 24 } 25 System. out.println(Thread.currentThread().getName()+"..."+ num); 26 } 27 System. out.println("over" ); 28 } 29 }
1 class StopThread implements Runnable{ 2 private boolean flag = true; 3 public synchronized void run(){ 4 while(flag){ 5 try{ 6 wait(); 7 } catch(Exception e){ 8 System.out.println(e); 9 flag = false; 10 } 11 System.out.println(Thread.currentThread().getName() ); 12 } 13 } 14 public void setFlag(){ 15 flag = false; 16 } 17 } 18 19 class StopThreadDemo{ 20 public static void main(String[] args){ 21 StopThread st = new StopThread(); 22 Thread t1 = new Thread(st).start(); 23 Thread t2 = new Thread(st).start(); 24 int num = 0; 25 while(true){ 26 if(num++ == 50){ 27 t1.interrupt(); 28 t2.interrupt(); 29 break; 30 } 31 System.out.println( Thread.currentThread().getName()+"..." + num); 32 } 33 System.out.println( "over"); 34 } 35 }
2、守护线程
setDaemon,将该线程标记为守护线程或用户线程。正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。 setDaemon(boolean):将线程标记为后台线程,后台线程和前台线程一样,开启,一样抢执行权运行,只有在结束时,有区别,当前台线程都运行结束后,后台线程会自动结束。
3、join方法
当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。join可以用来临时加入线程执行。
4、 setPriority方法
用来设置优先级
MAX_PRIORITY 最高优先级10
MIN_PRIORITY 最低优先级1
NORM_PRIORITY 分配给线程的默认优先级
5、yield方法
暂停当前线程,让其他线程执行,可以让线程释放执行权
6、toString方法
返回该线程的字符串表示形式,包括线程名称、优先级和线程组
标签:
原文地址:http://www.cnblogs.com/521Android/p/4731504.html