黑马程序员_Java基础:多线程总结
2015-08-05 00:24
751 查看
------- android培训、java培训、期待与您交流! ----------
一、多线程的概念
进程和线程经常会被人混淆,那是因为对它们的概念不明确。就拿我们平时使用的操作系统来说,它是多任务的操作系统,而多线程就是实现多任务的一种方式。
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。
线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如平时下载的软件迅雷进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。
说起多线程,给很多人得印象就是“同时”执行。但是多线程在并发执行的时候,其实是在线程之间快速轮换执行的,只不过轮换的速度很快,所以有“同时”执行的效果。
二、多线程的优缺点
优点:
(1)资料利用率更好。
(2)部分程序设计更加简单。
(3)程序响应更快。
(4)简化异步时间的处理(服务器)。
缺点:
(1)部分程序设计更复杂。
(2)增加cpu上下文切换开销。
(3)增加资源消耗。
三、多线程的创建和使用
在java中提供了对象线程这类事物的描述,该类是Thread。线程的常用创建和启动方式有两种:
1.继承Thread类,子类覆盖父类中的run方法,把需要多线程执行的代码存放在run方法中。然后创建子类的对象同时线程也会被创建起来。最后通过子类调用start方法开启线程。
具体如下面代码:
2.实现Runnable接口,子类覆盖接口中的run方法,把需要多线程执行的代码存放在run方法中。然后通过Thread创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。最后Thread类对象调用Start方法开启线程。
具体如下代码:
以上两种创建方式的区别:
(1)继承Thread:线程代码存放Thread子类run方法中。
(2)实现Runnable:线程代码存在接口的子类的run方法,使用起来更加灵活,可以避免单继承局限性,因为java中的对象是单继承多实现的。
另外通过以上的运行可以发现,运行结果每一次都不同,这是因为线程需要获取cpu的执行权时才能执行。在多个线程中,cpu执行到谁,谁就运行。我们可以把形象的把多个线程在抢夺cpu的资源,这也是多线程随机性的体现。需要明确的一点是,在某一个时刻,只能有一个线程在运行(多核除外)。
四、线程的状态转换
下面是线程状态转换示意图:
从上图可以看出,一个线程从执行到结束,会经历几种状态,下面对这几种状态进行解释。
1.创建线程:也可以说叫new状态,就是把线程建立起来。
2.阻塞状态:当线程start开启后,不一定马上进入运行状态,而是可能先进入阻塞状态,阻塞状态表示程序准备就绪,等待系统的调度。也可以说是具有运行权,但没有执行权。
3.运行状态:线程接收到系统的调度,执行起来。也就是说线程具有执行权。
4.冻结状态:当线程处于处于sleep,wait等状态时,即是冻结状态,表示线程还是活的,但是没有运行权。另外当一个线程休眠或者被唤醒结束时,不一定马上进入运行状态,而是可能先进入阻塞状态,等待系统调度,当被调度具有执行权时,再进入运行状态。
5.消亡状态:就是线程结束。
当我们对线程各种状态有了基本了解后,设计多线程时才能更加效率准确。
五、多线程的同步
当多个线程间通讯,也就是多个线程的同时操作同一资源时,如果一个线程正在访问修改一些数据的同时,另一个线程也在修改这些数据,那么前一个线程的修改操作后就得到错误数据,造成安全隐患。
解决办法:
当有多条对共享数据进行操作的语句时,要让一个线程都执行完,而在执行过程中,其他线程不可以参与执行,也就是实现同步。
实现同步的方法:
java中对于实现同步提供了解决方法。
1.synchronized同步代码块:
使用同步代码块的前提,是具有两个或以上的线程,而且多个线程必须使用同一把锁。当线程持有锁时可以在同步中执行,而没有持有锁的线程即使获取cpu的执行权,也无法执行同步代码块里的代码。同时,也因为同步的特性,当多个线程判断锁时,有较为消耗资源的缺点。以下是同步代码块的应用:
从结果可以看出没有错票,实现同步。
2.synchronized同步函数:
synchronized同步函数和synchronized同步代码块的功能是一样的,不同的是在同步函数中,synchronized修饰的是函数。
另外要注意,synchronized同步函数的锁对象有两种情况:
(1)当synchronized修饰的函数不是静态函数时,那么synchronized对应的锁对象是this,即是调用方法的对象。看以下代码验证:
从结果可以看出没有错票,实现同步。
(2)当synchronized修饰的函数是静态函数时,那么synchronized对应的锁对象是函数所在类的字节码对象(xxx.class),因为静态方法是属于类,不属于对象。看以下代码验证:
从结果可以看出没有错票,实现同步。
在synchronized同步代码块和同步函数中,可以使用wait(),notify(),notifyAll()来控制线程,这三个方法的使用前提就是必须使用在同步中,而且使用它们的时候要标识它们所属的同步的锁,它们的作用是:
①wait():释放cpu执行权,释放锁。也就是说,当线程wait后就处于冻结状态。
②notify():唤醒第一个wait的线程。
③notify():唤醒全部等待的线程。
使用这三种方法可以实现等待唤醒机制,以下是使用的实例代码:
运行结果是不停的生产和消费,但生产和消费的数目总是一样的。说明程序通过标记成功控制每生产一个商品就消费一个,并且实现了多线程的同步。
同时,等待唤醒机制要避免死锁的出现。所谓死锁就是同步中嵌套同步,然后多线程在执行时相互取得不同的锁后不释放,造成程序一致等待。请看下面例子:
运行结果是程序一直等待不动。
另外需要注意的,wait()和sleep()的区别:
①wait()是Object类中的方法;sleep()是Thread类中的方法。
②它们两个都可以让线程冻结,wait()需要被唤醒;而sleep在冻结一定时间后会自动唤醒。
③wait()释放cpu执行权的同时,会释放锁;而sleep()只释放执行权,不会释放锁。
(3)在JDk1.5中提供了更加灵活的多线程同步方法:Lock。相应地在使用Lock同步时,也可以使用Condition中的await(),signal();signalAll();来实现多线程等待唤醒机制。以下是具体使用例子:
运行结果是不停的生产和消费,但生产和消费的数目总是一样的。说明程序通过标记成功控制每生产一个商品就消费一个,并且实现了多线程的同步。
六、多线程的停止
多线程的stop()已过时,所以想要多线程停止的方法只有通过run方法结束。多线程的代码通常都是摆在循环结构中的,所以只要控制循环,就可以让run方法结束,也就是线程结束。
但是,如果线程处于冻结状态(等待,睡眠),读不到循环的标记,那么程序就无法停止。所以在没有指定方式让冻结的线程恢复到运行状态中时,可以使用Thread类中的interrupt()方法强行让线程恢复到运行状态中,这样线程就能继续执行读取到循环标记,从而停止线程。以下是例子:
运行结果是程序顺利结束。
七、线程中的其他常见方法
1.join:
当A线程执行到了B线程的.join()方法时,A机会等待。等B线程都执行完,A线程才会执行。
join可以用来临时加入线程执行。
2.setDaemon(boolean):
将线程标记为后台程序(守护线程),后台线程和前台线程一样开启,一样抢执行权运行。
只有在结束时有区别。当前台线程都运行结束后,后台程序会自动结束。
3.setPriority:
更改线程优先级别:级别为(1~10),线程默认优先级别为5。
Thread.MAX_PRIORITY = 10;
Thread.NORM_PRIORITY = 5;
Thread.MIN_PRIORITY = 1。
4.yield:
暂停正在执行的线程,并执行其他线程。
以下是它们的使用例子:
运行结果是t1的0线程全部要执行完后,再把执行主线程main执行完,最后才执行t2的1线程。
多线程总结完毕。
一、多线程的概念
进程和线程经常会被人混淆,那是因为对它们的概念不明确。就拿我们平时使用的操作系统来说,它是多任务的操作系统,而多线程就是实现多任务的一种方式。
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。
线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如平时下载的软件迅雷进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。
说起多线程,给很多人得印象就是“同时”执行。但是多线程在并发执行的时候,其实是在线程之间快速轮换执行的,只不过轮换的速度很快,所以有“同时”执行的效果。
二、多线程的优缺点
优点:
(1)资料利用率更好。
(2)部分程序设计更加简单。
(3)程序响应更快。
(4)简化异步时间的处理(服务器)。
缺点:
(1)部分程序设计更复杂。
(2)增加cpu上下文切换开销。
(3)增加资源消耗。
三、多线程的创建和使用
在java中提供了对象线程这类事物的描述,该类是Thread。线程的常用创建和启动方式有两种:
1.继承Thread类,子类覆盖父类中的run方法,把需要多线程执行的代码存放在run方法中。然后创建子类的对象同时线程也会被创建起来。最后通过子类调用start方法开启线程。
具体如下面代码:
class Demo extends Thread { //继承Thread类。 public void run() { //覆盖run方法。 for(int x=0; x<60; x++) System.out.println("线程1----"+x); } } public class ThreadDemo { public static void main(String[] args) { Demo d = new Demo();//创建好一个线程。 d.start(); //开启线程并执行该线程的run方法。 //d.run(); //注意,这里仅仅是对象调用方法。而线程创建了,并没有运行。 for(int x=0; x<60; x++) System.out.println("主线程--"+x); } }
2.实现Runnable接口,子类覆盖接口中的run方法,把需要多线程执行的代码存放在run方法中。然后通过Thread创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。最后Thread类对象调用Start方法开启线程。
具体如下代码:
class Demo_2 implements Runnable { private int x = 100; public void run() { while(true) { if(x>0) // Thread.currentThread().getName()获取当前线程的名称。 System.out.println(Thread.currentThread().getName()+"....x : "+ x--); } } } public class ThreadDemo_2 { public static void main(String[] args) { Demo_2 d = new Demo_2(); Thread t1 = new Thread(d);//创建了一个线程; Thread t2 = new Thread(d);//创建了一个线程; Thread t3 = new Thread(d);//创建了一个线程; Thread t4 = new Thread(d);//创建了一个线程; t1.start(); t2.start(); t3.start(); t4.start(); } }
以上两种创建方式的区别:
(1)继承Thread:线程代码存放Thread子类run方法中。
(2)实现Runnable:线程代码存在接口的子类的run方法,使用起来更加灵活,可以避免单继承局限性,因为java中的对象是单继承多实现的。
另外通过以上的运行可以发现,运行结果每一次都不同,这是因为线程需要获取cpu的执行权时才能执行。在多个线程中,cpu执行到谁,谁就运行。我们可以把形象的把多个线程在抢夺cpu的资源,这也是多线程随机性的体现。需要明确的一点是,在某一个时刻,只能有一个线程在运行(多核除外)。
四、线程的状态转换
下面是线程状态转换示意图:
从上图可以看出,一个线程从执行到结束,会经历几种状态,下面对这几种状态进行解释。
1.创建线程:也可以说叫new状态,就是把线程建立起来。
2.阻塞状态:当线程start开启后,不一定马上进入运行状态,而是可能先进入阻塞状态,阻塞状态表示程序准备就绪,等待系统的调度。也可以说是具有运行权,但没有执行权。
3.运行状态:线程接收到系统的调度,执行起来。也就是说线程具有执行权。
4.冻结状态:当线程处于处于sleep,wait等状态时,即是冻结状态,表示线程还是活的,但是没有运行权。另外当一个线程休眠或者被唤醒结束时,不一定马上进入运行状态,而是可能先进入阻塞状态,等待系统调度,当被调度具有执行权时,再进入运行状态。
5.消亡状态:就是线程结束。
当我们对线程各种状态有了基本了解后,设计多线程时才能更加效率准确。
五、多线程的同步
当多个线程间通讯,也就是多个线程的同时操作同一资源时,如果一个线程正在访问修改一些数据的同时,另一个线程也在修改这些数据,那么前一个线程的修改操作后就得到错误数据,造成安全隐患。
解决办法:
当有多条对共享数据进行操作的语句时,要让一个线程都执行完,而在执行过程中,其他线程不可以参与执行,也就是实现同步。
实现同步的方法:
java中对于实现同步提供了解决方法。
1.synchronized同步代码块:
使用同步代码块的前提,是具有两个或以上的线程,而且多个线程必须使用同一把锁。当线程持有锁时可以在同步中执行,而没有持有锁的线程即使获取cpu的执行权,也无法执行同步代码块里的代码。同时,也因为同步的特性,当多个线程判断锁时,有较为消耗资源的缺点。以下是同步代码块的应用:
/* 多个窗口销售1000张票,票号不重复。 */ class Ticket implements Runnable { private int tick = 1000; Object obj = new Object(); public void run() { while(true) { synchronized(obj) { //同步代码块,需要传递一个对象参数,可以把对象看成是锁。 //此处两条语句操作tick,多个线程执行时,可能出现安全隐患,需要同步 if(tick>0) System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--); } } } } public class TicketDemo { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } }
从结果可以看出没有错票,实现同步。
2.synchronized同步函数:
synchronized同步函数和synchronized同步代码块的功能是一样的,不同的是在同步函数中,synchronized修饰的是函数。
另外要注意,synchronized同步函数的锁对象有两种情况:
(1)当synchronized修饰的函数不是静态函数时,那么synchronized对应的锁对象是this,即是调用方法的对象。看以下代码验证:
/* 非静态同步函数用的是哪一个锁呢? 非静态函数需要被对象调用。那么函数都有一个所属对象引用。就是this。 所以非静态同步函数使用的锁是this。 通过该程序进行验证。 使用两个线程来买票。 一个线程在同步代码块中。 一个线程在同步函数中。 都在执行买票动作。 */ class Ticket implements Runnable { private int tick = 1000; Object obj = new Object(); boolean flag = true; //定义标记,不同标记执行不同的代码。 public void run() { if(flag) { while(true) { synchronized(this) { if(tick>0) { //让线程停顿,方便验证结果。 try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"....code : "+ tick--); } } } } else while(true) show(); } public synchronized void show(){ //非静态同步代函数 if(tick>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--); } } } public class ThisLockDemo { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try{Thread.sleep(10);}catch(Exception e){} //这里让线程停顿,方便验证同步。 t.flag = false; //通过修改标记,t2线程执行不同的语句。 t2.start(); } }
从结果可以看出没有错票,实现同步。
(2)当synchronized修饰的函数是静态函数时,那么synchronized对应的锁对象是函数所在类的字节码对象(xxx.class),因为静态方法是属于类,不属于对象。看以下代码验证:
/* 如果同步函数被静态修饰后,使用的锁是什么呢? 通过验证,发现不在是this。因为静态方法中也不可以定义this。 静态进内存是,内存中没有本类对象,但是一定有该类对应的字节码文件对象。 类名.class 该对象的类型是Class 静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 类名.class */ class Ticket implements Runnable { private static int tick = 1000; //Object obj = new Object(); boolean flag = true; public void run() { if(flag) { while(true) { synchronized(Ticket.class) { if(tick>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"....code : "+ tick--); } } } } else while(true) show(); } public static synchronized void show() { //静态同步代函数 if(tick>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--); } } } class StaticMethodDemo { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try{Thread.sleep(10);}catch(Exception e){} t.flag = false; t2.start(); } }
从结果可以看出没有错票,实现同步。
在synchronized同步代码块和同步函数中,可以使用wait(),notify(),notifyAll()来控制线程,这三个方法的使用前提就是必须使用在同步中,而且使用它们的时候要标识它们所属的同步的锁,它们的作用是:
①wait():释放cpu执行权,释放锁。也就是说,当线程wait后就处于冻结状态。
②notify():唤醒第一个wait的线程。
③notify():唤醒全部等待的线程。
使用这三种方法可以实现等待唤醒机制,以下是使用的实例代码:
/* 等待唤醒机制。 也就是常见的生产者消费者问题,举个例子,生产者没生产一个商品,就要被消费者消费。 1,当多个生产者消费者出现时。 需要让获取执行权的线程判断标记。 通过while完成。 2,需要将对方的线程唤醒。 仅仅notify,是不可以的。 因为有可能出现只唤醒本方,导致所有线程都在等待。 所以要通过notifyAll形式来完成。 对于多个生产者和消费者。 为什么要定义while判断标记。 原因:让被唤醒的线程再一次判断标记。 */ class Resource { private String name; private int count = 1; private boolean flag = false; public synchronized void set(String name) { while(flag) try{this.wait();}catch(Exception e){} //当线程执行到这里会进入等待状态,释放锁。 this.name = name+"--"+count++; //注意下面输出语句name前必须加this,否则会直接访问局部变量中的name。 System.out.println(Thread.currentThread().getName()+"生产者:"+this.name); flag = true; this.notifyAll(); //唤醒所有等待的线程。 } public synchronized void out() { while(!flag) try{this.wait();}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"消费者:--"+this.name); flag = false; this.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(); } } class ProducerConsumerDemo { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } }
运行结果是不停的生产和消费,但生产和消费的数目总是一样的。说明程序通过标记成功控制每生产一个商品就消费一个,并且实现了多线程的同步。
同时,等待唤醒机制要避免死锁的出现。所谓死锁就是同步中嵌套同步,然后多线程在执行时相互取得不同的锁后不释放,造成程序一致等待。请看下面例子:
class Test implements Runnable { private boolean flag; Test(boolean flag) { this.flag = flag; } public void run() { if(flag) { while(true) { synchronized(MyLock.locka) { System.out.println(Thread.currentThread().getName()+"...if locka "); synchronized(MyLock.lockb) { System.out.println(Thread.currentThread().getName()+"..if lockb"); } } } } else { while(true) { synchronized(MyLock.lockb) { System.out.println(Thread.currentThread().getName()+"..else lockb"); synchronized(MyLock.locka) { System.out.println(Thread.currentThread().getName()+".....else locka"); } } } } } } class MyLock { static Object locka = new Object(); static Object lockb = new Object(); } class DeadLockTest { public static void main(String[] args) { Thread t1 = new Thread(new Test(true)); Thread t2 = new Thread(new Test(false)); t1.start(); t2.start(); } }
运行结果是程序一直等待不动。
另外需要注意的,wait()和sleep()的区别:
①wait()是Object类中的方法;sleep()是Thread类中的方法。
②它们两个都可以让线程冻结,wait()需要被唤醒;而sleep在冻结一定时间后会自动唤醒。
③wait()释放cpu执行权的同时,会释放锁;而sleep()只释放执行权,不会释放锁。
(3)在JDk1.5中提供了更加灵活的多线程同步方法:Lock。相应地在使用Lock同步时,也可以使用Condition中的await(),signal();signalAll();来实现多线程等待唤醒机制。以下是具体使用例子:
import java.util.concurrent.locks.*; /* JDk1.5中提供了多线程升级解决方案。 将同步隐式锁Syncronized替换成显式Lock操作。 将Object中的wait,notify,notifyAll,替换成Condition对象。 该对象可以通过Lock锁进行获取。 该示例中,实现了本方只唤醒对方的操作。 Lock:替换了synchronized lock; unlock; newCondition(); Condition:替代了Object中方法wait notify notifyAll await(); signal(); signalAll(); */ class Resource { private String name; private int count = 1; private boolean flag = false; private Lock lock = new ReentrantLock(); //创建同步锁。 private Condition condition_pro = lock.newCondition(); //通过Lock建立不同的条件。 private Condition condition_con = lock.newCondition(); public void set(String name)throws InterruptedException { try { lock.lock(); while (flag) condition_pro.await(); this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"生产者:"+this.name); flag = true; condition_con.signal(); //实现只唤醒消费者。 } finally { //利用finally特性保证最后能释放锁。 lock.unlock(); } } public void out()throws InterruptedException { try { lock.lock(); while(!flag) condition_con.await(); System.out.println(Thread.currentThread().getName()+"----消费者:"+this.name); flag = false; condition_pro.signal(); //实现只唤醒生产者。 } finally { //利用finally特性保证最后能释放锁。 lock.unlock(); } } } class Producer implements Runnable { private Resource r; Producer(Resource r) { this.r = r; } public void run() { try { while(true) r.set("+商品+"); } catch (InterruptedException e){ } } } class Consumer implements Runnable { private Resource r; Consumer(Resource r) { this.r = r; } public void run() { try { while(true) r.out(); } catch (InterruptedException e) { } } } class ProducerConsumerDemo2 { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } }
运行结果是不停的生产和消费,但生产和消费的数目总是一样的。说明程序通过标记成功控制每生产一个商品就消费一个,并且实现了多线程的同步。
六、多线程的停止
多线程的stop()已过时,所以想要多线程停止的方法只有通过run方法结束。多线程的代码通常都是摆在循环结构中的,所以只要控制循环,就可以让run方法结束,也就是线程结束。
但是,如果线程处于冻结状态(等待,睡眠),读不到循环的标记,那么程序就无法停止。所以在没有指定方式让冻结的线程恢复到运行状态中时,可以使用Thread类中的interrupt()方法强行让线程恢复到运行状态中,这样线程就能继续执行读取到循环标记,从而停止线程。以下是例子:
class StopThread implements Runnable { private boolean flag = true; public synchronized void run() { while(flag) { try { wait(); } catch (InterruptedException e) { //注意这里接收到的InterruptedException是t1.interrupt()和t2.interrupt()抛出的异常。 System.out.println(Thread.currentThread().getName()+".........Exception"); changeFlag(); //最后记住要改标记才能让线程恢复运行后停止。 } System.out.println(Thread.currentThread().getName()+"...run"); } } public void changeFlag() { flag = false; } } 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 num = 0; while(true) { if(num++ == 60) { // st.changeFlag(); t1.interrupt(); //清除线程中断状态,但是会抛出InterruptedException异常。 t2.interrupt(); break; } System.out.println(Thread.currentThread().getName()+"..."+num); } System.out.println("over"); } }
运行结果是程序顺利结束。
七、线程中的其他常见方法
1.join:
当A线程执行到了B线程的.join()方法时,A机会等待。等B线程都执行完,A线程才会执行。
join可以用来临时加入线程执行。
2.setDaemon(boolean):
将线程标记为后台程序(守护线程),后台线程和前台线程一样开启,一样抢执行权运行。
只有在结束时有区别。当前台线程都运行结束后,后台程序会自动结束。
3.setPriority:
更改线程优先级别:级别为(1~10),线程默认优先级别为5。
Thread.MAX_PRIORITY = 10;
Thread.NORM_PRIORITY = 5;
Thread.MIN_PRIORITY = 1。
4.yield:
暂停正在执行的线程,并执行其他线程。
以下是它们的使用例子:
class Demo implements Runnable { public void run() { for (int x= 0; x<70; x++){ System.out.println(Thread.currentThread().getName()+"..."+x); Thread.yield(); } } } class JoinDemo { public static void main(String[] args)throws Exception { Demo d = new Demo(); Thread t1 = new Thread(d); Thread t2 = new Thread(d); // t1.setDaemon(true); //设置为守护线程,一旦前台所有线程结束,守护线程会自动结束。 // t1.setPriority(Thread.MAX_PRIORITY); //设置线程优先级别,级别越大,线程得到cpu执行权概率就越大。 t1.start(); t1.join(); t2.start(); for (int x=0; x<80; x++) System.out.println("main..."+x); System.out.println("over"); } }
运行结果是t1的0线程全部要执行完后,再把执行主线程main执行完,最后才执行t2的1线程。
多线程总结完毕。
相关文章推荐
- js一道面试题
- StackOverflow程序员推荐:每个程序员都应读的30本书
- 为啥面试需要Aggressive?
- 背包算法解决一道华为面试题
- leetcode面试准备:Contains Duplicate I && II
- 黑马程序员_Java_String
- 黑马程序员--文件字符输入输出函数的应用
- 黑马程序员——Java String类
- 黑马程序员——Java 多线程
- 操作系统面试题转载
- 黑马程序员——Java 面向对象_包
- 面试题总结
- 黑马程序员——Java 面向对象_异常
- 黑马程序员——Java基础---跳转控制语句与循环语句练习
- 黑马程序员——Java之String类、基本数据类型对象包装类等
- 黑马程序员——Java 面向对象_多态
- 爱奇艺前端面试题3
- 黑马程序员——Java基础--键盘录入数据与流程控制语句
- (剑指Offer)面试题55:字符流中第一个不重复的字符
- 黑马程序员——Java 面向对象_继承