黑马程序员-多线程
2015-10-29 20:53
375 查看
——-android培训java培训期待与您交流!———-
线程:进程中一个独立的控制单元,线程控制着进程的执行。
多线程的意义:提高cpu的使用率。从而提高了应用程序的使用率。
线程和线程共享”堆内存和方法区内存”,栈是独立的,一个线程一个栈
Java程序的运行原理:java命令会启动java虚拟机,启动jvm等于启动了一个应用程序,表示启动了一个进程。该进程会自动启动一个”主线程”,然后主线程去调用某个类的main方法。所以main方法运行在主线程中。
第一种方式:继承Thread类;复写Thread类中的run方法(将自定义的代码存在run方法,让线程调用);调用线程的start方法,启动线程,调用run方法。
start:开启线程并执行该线程的run方法。
练习
新建:用new语句创建完成
就绪:执行start后
运行:占用cpu时间
阻塞:执行了wait语句、执行了sleep语句和等待某个对象锁,等待输入的场合
消亡:退出run()方法
线程的几个方法:
1.static Thread currentThread():获取当前线程对象。
2.getName():获取线程的名称。
3.设置线程名称:setName或者构造函数。
步骤:定义类实现Runnable接口;覆盖Runnable接口中的run方法;通过Thread类建立线程对象;将Runable接口的子类对象作为实际参数传递给Thread类的构造函数;调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
实现方式和继承方式有什么区别:
1.实现方式的好处:避免了单继承的局限性,在定义线程时,建议使用实现方式。
2. 区别:
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable:线程代码存在接口的子类的run方法
打印的结果为:
这是为何?这是因为共享了同一个对象的的成员变量s,两个线程同时对其进行操作,所以产生了上述为题。这个结果造成的现象称为线程不安全问题。
解决方法:对多条线程操作共享数据的语句,只能让一个线程都执行完,在执行过程过中,其他线程不可以参与执行。
Java对于多线程的安全问题提供了解决方式:同步代码块
对于上述的例子修改如下:
synchronized同步代码块如同给对象加锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获取了cpu的执行权,也进不到同步代码块中,因为没有获取锁。
同步的前提:
1. 必须要有两个或者两个以上的线程
2. 必须是多个线程使用同一个锁
必须保证同步中只能有一个线程在运行
好处和弊端:
1. 好处:解决了多线程的安全问题
2. 弊端:多个线程需要判断锁,较为消耗资源。
同步有两种表示:同步代码块和同步函数。
如何找同步:
1. 明确哪些代码是多线程运行代码。
2. 明确共享数据。
3. 明确多线程运行代码中那些语句是操作共享数据的。
同步函数例子:
静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。
静态的同步方法,使用的锁是该方法所在类的字节码文件对象。也就是
等待唤醒机制
wait();notify();notifyall();都是用在同步中,因为要对持有监视器(对象锁)的线程操作,而同步中才有锁。
这些操作方法定义在Object类中。因为这些方法在操作同步中线程时,都必须要标识他们所操作线程只有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。不可以对不同锁中的线程进行唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
示例2:(JDK1.5版本新特性。)
将同步Synchronized替换成显式Lock操作。
将Object中的wait,notify,notifyAll替换成了Condition对象,该对象可以用Lock锁来进行获取。
Lock:替换了Synchronized封装成了lock、unlock、newCondition()。
Condition:替换了Object、wait、notify、notifyAll封装成了await()、signal()、signalAll().
停止方法1:run方法结束。开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。
停止方法2:使用interrupt()方法。结束线程的冻结状态(sleep、wait、join方法),使线程回到运行状态中来。也就是靠异常机制来结束线程。
语法:
注意:该方法必须在启动线程前调用。
join方法
也就是抢夺cpu的执行权。可以用来临时加入线程执行。
特点:当a线程执行到了b线程的join方法,a就会等待,等b线程都执行完,a才会从冻结状态恢复到运行状态执行。
语法:
线程优先级
目前CPU使用权争夺有两种调度模型:分时调度模型和抢占式调度模型,Java 使用抢占式调度模型。
分时调度模型:所有线程轮流使用CPU 的使用权,平均分配每个线程占用CPU 的时间片
抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU 时间片相对多一些。
线程优先级为了:MAX_PRIORITY(最高级为10),MIN_PRIORITY(最低级为1),NORM_PRIORITY(默认及为5)。优先级为:1-10。优先级高的线程只能说明能抢占的cpu执行权较多些,执行的时间较多些。
线程启动后不能再次设置优先级。必须在线程启动前设置优先级。
概述
进程:是一个正在执行中的程序,每一个进程执行都有一个执行的顺序。该顺序是一个执行路径,或者叫一个控制单元。一个进程中至少有一个线程。线程:进程中一个独立的控制单元,线程控制着进程的执行。
多线程的意义:提高cpu的使用率。从而提高了应用程序的使用率。
线程和线程共享”堆内存和方法区内存”,栈是独立的,一个线程一个栈
Java程序的运行原理:java命令会启动java虚拟机,启动jvm等于启动了一个应用程序,表示启动了一个进程。该进程会自动启动一个”主线程”,然后主线程去调用某个类的main方法。所以main方法运行在主线程中。
创建线程
JAVA已经提供了对线程事物的描述的类即Thread类。有两种方式创建线程。第一种方式:继承Thread类;复写Thread类中的run方法(将自定义的代码存在run方法,让线程调用);调用线程的start方法,启动线程,调用run方法。
package com.sergio.thread; /** * Created by Sergio on 2014/12/8. */ public class ThreadDemo{ public static void main(String[] args) { //创建线程任务对象 ThreadCreate td = new ThreadCreate(); //启动线程,而不是直接调用run方法。线程的真真的执行是由java线程调度机制完成的。 td.start(); for(int x = 0; x < 1000; x++) { System.out.println("Demo " + x); } } } //创建需要执行人物的类,继承之Thread类 class ThreadCreate extends Thread { //复写Thread类中的run方法。定义自己的内容 public void run(){ for(int x = 0; x < 100; x++){ System.out.println("Heall word! " + x); } } }
run和start的特点
run:仅仅是对象调用方法,并没有运行线程(Thread类的run方法用于存储线程要运行的代码)。start:开启线程并执行该线程的run方法。
练习
package com.sergio.thread; /** * Created by Sergio on 2014/12/8. * 创建两个线程与main线程交替运行 */ public class ThreadDemo1 { public static void main(String[] args) { //创建两个线程对象 ThreadCreate1 td1 = new ThreadCreate1("线程一"); ThreadCreate1 td2 = new ThreadCreate1("线程二"); //启动两个线程 td1.start(); td2.start(); for(int x =0; x < 60; x++) { System.out.println("main run..." + x); } } } //创建执行任务的线程继承thread类 class ThreadCreate1 extends Thread { private String name; ThreadCreate1(String name) { this.name = name; } //复写run方法 public void run(){ for(int x = 0; x < 60; x++) { System.out.println(name + "run..." + x); } } }
多线程声明周期
如图:新建:用new语句创建完成
就绪:执行start后
运行:占用cpu时间
阻塞:执行了wait语句、执行了sleep语句和等待某个对象锁,等待输入的场合
消亡:退出run()方法
获取多线程对象及名称
线程都有自己的默认名称:Thread-编号该编号从0开始。
线程的几个方法:
1.static Thread currentThread():获取当前线程对象。
2.getName():获取线程的名称。
3.设置线程名称:setName或者构造函数。
package com.sergio.thread; /** * Created by Sergio on 2014/12/8. */ public class ThreadDemo1 { public static void main(String[] args) { //创建两个线程对象 ThreadCreate1 td1 = new ThreadCreate1("线程一"); ThreadCreate1 td2 = new ThreadCreate1("线程二"); //启动两个线程 td1.start(); td2.start(); } } //创建执行任务的线程继承thread类 class ThreadCreate1 extends Thread { ThreadCreate1(String name) { //给线程命名 super(name); } //复写run方法 public void run(){ for(int x = 0; x < 60; x++) { //Thread.currentThread()通过此静态方法获取当前线程对象 System.out.println(Thread.currentThread().getName() + "run..." + x); } } }
创建线程
创建线程的第二种方式:实现Runnable接口。步骤:定义类实现Runnable接口;覆盖Runnable接口中的run方法;通过Thread类建立线程对象;将Runable接口的子类对象作为实际参数传递给Thread类的构造函数;调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
package com.sergio.thread; import sun.security.krb5.internal.Ticket; /** * Created by Sergio on 2014/12/9. */ public class RunnableThreadDemo { public static void main(String[] args) { //创建卖票类实例对象 RunnableThreadCreate t = new RunnableThreadCreate(); //将通过Thread类建立线程对象;将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数 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(); } } //实现Runnable接口,模拟卖票功能类 class RunnableThreadCreate implements Runnable { private int ticket = 100; @Override public void run() { while(true) { if(ticket > 0) { System.out.println(Thread.currentThread().getName() + "售出票号" + ticket--); } } } }
实现方式和继承方式有什么区别:
1.实现方式的好处:避免了单继承的局限性,在定义线程时,建议使用实现方式。
2. 区别:
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable:线程代码存在接口的子类的run方法
多线程安全
先来看一个例子:package com.sergio.thread; /** * Created by Sergio on 2014/12/9. */ public class TreadSafeDemo { public static void main(String[] args) { // ThreadSafeCreateDemo ts = new ThreadSafeCreateDemo(); Thread t1 = new Thread(ts, "t1"); t1.start(); Thread t2 = new Thread(ts, "t2"); t2.start(); } } class ThreadSafeCreateDemo implements Runnable { //成员变量s,作为累加变量 private int s = 0; @Override public void run() { //计算1-10的相加合 for(int i = 0; i < 10;i++) { s += i; } System.out.println(Thread.currentThread().getName() + ", s = " + s); } }
打印的结果为:
t1, s = 45 t2, s = 90
这是为何?这是因为共享了同一个对象的的成员变量s,两个线程同时对其进行操作,所以产生了上述为题。这个结果造成的现象称为线程不安全问题。
解决方法:对多条线程操作共享数据的语句,只能让一个线程都执行完,在执行过程过中,其他线程不可以参与执行。
Java对于多线程的安全问题提供了解决方式:同步代码块
synchronized(对象) { 需要被同步的代码 }
对于上述的例子修改如下:
package com.sergio.thread; /** * Created by Sergio on 2014/12/9. */ public class TreadSafeDemo { public static void main(String[] args) { ThreadSafeCreateDemo ts = new ThreadSafeCreateDemo(); Thread t1 = new Thread(ts, "t1"); t1.start(); Thread t2 = new Thread(ts, "t2"); t2.start(); } } class ThreadSafeCreateDemo implements Runnable { //成员变量s,作为累加变量 private int s = 0; //增加关键字synchronized来给对象加锁使代码同步安全问题得到解决,但是会带来效率变慢问题 @Override public synchronized void run() { //计算1-10的相加合 synchronized (this){ for(int i = 0; i < 10;i++) { s += i; } } System.out.println(Thread.currentThread().getName() + ", s = " + s); s = 0; } }
synchronized同步代码块如同给对象加锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获取了cpu的执行权,也进不到同步代码块中,因为没有获取锁。
同步的前提:
1. 必须要有两个或者两个以上的线程
2. 必须是多个线程使用同一个锁
必须保证同步中只能有一个线程在运行
好处和弊端:
1. 好处:解决了多线程的安全问题
2. 弊端:多个线程需要判断锁,较为消耗资源。
同步有两种表示:同步代码块和同步函数。
如何找同步:
1. 明确哪些代码是多线程运行代码。
2. 明确共享数据。
3. 明确多线程运行代码中那些语句是操作共享数据的。
同步函数例子:
package com.sergio.thread; /** * Created by Sergio on 2014/12/9. * 两个客户同时往一个账户中存钱,每次100,分别分三次寸 */ public class ThreadBankDemo { public static void main(String[] args) { Cus c = new Cus(); Thread t1 = new Thread(c, "t1"); t1.start(); Thread t2 = new Thread(c, "t2"); t2.start(); } } //创建银行类 class Bank { //存钱的成员变量 private int sum; //同步代码函数。存钱函数 public synchronized void add(int n) { sum = sum + n; System.out.println(sum); } } //客户存钱函数类实现多线程接口 class Cus implements Runnable { //创建银行类对象 Bank b = new Bank(); //需要多线程执行的代码 @Override public void run() { for(int x = 0; x < 3; x++) { //调用存钱的方法 b.add(100); } } }
同步函数锁
函数需要被对象调用,函数都有一个所属对象引用,就是this。所以同步函数使用的锁是this。public void run() { //this当前运行的对象引用 synchronized (this){ //计算1-10的相加合 for(int i = 0; i < 10;i++) { s += i; } System.out.println(Thread.currentThread().getName() + ", s = " + s); s = 0; } }
静态同步函数
静态方法中不可以定义this,没对象。静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。
类名.class该对象的类型是Class。
静态的同步方法,使用的锁是该方法所在类的字节码文件对象。也就是
类名.class。
//静态的 SinglePattern2实例对象变量 private static SinglePattern2 instance = null; //私有构造函数 private SinglePattern2(){} public static SinglePattern2 getInstance() { if(instance == null) { //静态同步函数调用方式类名.class synchronized (SinglePattern2.class) { if(instance == null) { instance = new SinglePattern2(); } } } return instance; }
死锁
概念:同步中嵌套同步但是锁对象不同。package com.sergio.thread; /** * 构建锁的机制的例子 * Created by Sergio on 2014/12/10. */ public class ThreadDeadLock2 { public static void main(String[] args) { Test test = new Test(false); Test test2 = new Test(true); Thread t = new Thread(test); Thread t2 = new Thread(test2); t.start(); t2.start(); } } class Test implements Runnable { //设置运行标志 private boolean flag; Test(boolean flag) { this.flag = flag; } //重写run方法,运行锁的机制。前提:同步中包含同步,但是锁的对象引用。 @Override public void run() { if(flag) { //锁locka对象的引用 synchronized (Lock.locka) { System.out.println("if locka"); //锁lock对象的引用 synchronized (Lock.lockb) { System.out.println("if lockb"); } } } else { //锁lockb对象的引用 synchronized (Lock.lockb) { System.out.println("else lockb"); //锁locka对象的引用 synchronized (Lock.locka) { System.out.println("else locka"); } } } } } //创建锁类 class Lock { //构建两个锁对象引用 static Object locka = new Object(); static Object lockb = new Object(); }
线程间通信
多个线程在操作同一个资源,但是操作的动作不同。package com.sergio.thread; /** * Created by Sergio on 2014/12/11. */ public class ThreadDemo2 { 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(); } } //需要操作的资源类 class Res { String name; String sex; } //输入操作线程类 class Input implements Runnable { private Res r; Input(Res r) { this.r = r; } //存资源运行方法 @Override public void run() { int x = 0; while(true) { //同步运行时的对象锁 synchronized (r) { if (x == 0) { r.name = "mike"; r.sex = "man"; } else { r.name = "丽丽"; r.sex = "女"; } } //改变运行条件标志值 x = (x + 1) % 2; } } } //输出操作线程类 class Output implements Runnable { private Res r; Output(Res r) { this.r = r; } //打印资源方式 @Override public void run() { while(true) { //同步运行时的同步锁 synchronized (r) { System.out.println(r.name + "------" + r.sex); } } } }
等待唤醒机制
package com.sergio.thread; /** * Created by Sergio on 2014/12/11. */ public class ThreadDemo2 { public static void main(String[] args) { Res r = new Res(); //启动两个线程 new Thread(new Input(r)).start(); new Thread(new Output(r)).start(); } } //需要操作的资源类 class Res { private String name; private String sex; //设置运行时的锁标志 private boolean flag = false; //同步输入锁 public synchronized void set(String name, String sex) { if (flag) { try { //让同步线程对象等待,并扑获异常。 this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.name = name; this.sex = sex; //改变同步锁运行时的标志值 flag = true; //唤醒同步线程池中的锁。也就是res对象 this.notify(); } //同步输出锁 public synchronized void out() { if (!flag) { try { //让同步线程对象等待,并扑获异常。 this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(name + "--------" + sex); //改变同步锁运行时的标志值 flag = false; //唤醒同步线程池中的锁。也就是res对象 this.notify(); } } //输入操作线程类 class Input implements Runnable { private Res r; Input(Res r) { this.r = r; } //存资源运行方法 @Override public void run() { int x = 0; while (true) { //交替输入信息 if (x == 0) { r.set("make", "man"); } else { r.set("丽丽", "女"); } //设置交替输入方法运行的标志 x = (x + 1) % 2; } } } //输出操作线程类 class Output implements Runnable { private Res r; Output(Res r) { this.r = r; } //打印资源方式 @Override public void run() { while (true) { r.out(); } } }
wait();notify();notifyall();都是用在同步中,因为要对持有监视器(对象锁)的线程操作,而同步中才有锁。
这些操作方法定义在Object类中。因为这些方法在操作同步中线程时,都必须要标识他们所操作线程只有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。不可以对不同锁中的线程进行唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
生产者消费模式
示例1:(JDK1.5以前方式书写)package com.sergio.thread; /** * Created by Sergio on 2015/1/3. */ 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(); } } /* 对于多个生产者和消费者。 为什么要定义while判断标记。 原因:让被唤醒的线程再一次判断标记。 为什么定义notifyAll, 因为需要唤醒对方线程。 因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。 */ //定义资源类 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++; 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 res; Producer(Resource res) { this.res = res; } public void run() { while (true) { res.set("+商品+"); } } } class Consumer implements Runnable { private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while (true) { res.out(); } } }
示例2:(JDK1.5版本新特性。)
将同步Synchronized替换成显式Lock操作。
将Object中的wait,notify,notifyAll替换成了Condition对象,该对象可以用Lock锁来进行获取。
Lock:替换了Synchronized封装成了lock、unlock、newCondition()。
Condition:替换了Object、wait、notify、notifyAll封装成了await()、signal()、signalAll().
package com.sergio.thread; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 生产者消费者模式 * Created by Sergio on 2015/1/3. */ class ProducerConsumerDemo { public static void main(String[] args) { Resource r = new Resource(); Producer2 pro = new Producer2(r); Consumer2 con = new Consumer2(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 Resource { //定义名称 private String name; //定义计数基数 private int count = 1; //定义线程运行标志 private boolean flag = false; //定义锁lock对象变量 private Lock lock = new ReentrantLock(); //定义状态condition_pro对象变量 private Condition condition_pro = lock.newCondition(); //定义状态condition_con对象变量 private Condition condition_con = lock.newCondition(); //定义生产者的方法 public void set(String name) throws InterruptedException { //获取当前锁锁住对象 lock.lock(); try { while (flag) { //使生产者对象锁等待,在函数上声明异常类 condition_pro.await(); } this.name = name + "--" + count++; System.out.println(Thread.currentThread().getName() + "生产者" + this.name); flag = true; //唤醒消费者对象锁 condition_con.signal(); } finally { //释放锁的动作一定要执行。 lock.unlock(); } } //消费者方法 public synchronized void out() throws InterruptedException { lock.lock(); try { while (!flag) { //使消费者对象锁等待。在函数上声明异常类 condition_con.await(); } System.out.println(Thread.currentThread().getName() + "...消费者..." + this.name); flag = false; //唤醒生产者对象锁 condition_pro.signal(); } finally { lock.unlock(); } } } //定义生产者 class Producer2 implements Runnable { private Resource res; Producer2(Resource res) { this.res = res; } public void run() { while (true) { try { res.set("商品"); } catch (Exception e) { e.printStackTrace(); } } } } //定义消费者 class Consumer2 implements Runnable { private Resource res; Consumer2(Resource res) { this.res = res; } @Override public void run() { while (true) { try { res.out(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
停止线程
stop方法已经过时。停止方法1:run方法结束。开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。
package com.sergio.thread; /** * 利用循环结构结束线程 * Created by Sergio on 2015/1/3. */ class StopThread { public static void main(String[] args) { StopThreadDemo sp = new StopThreadDemo(); Thread t1 = new Thread(sp); Thread t2 = new Thread(sp); t1.start(); t2.start(); //计数基数 int num = 0; while (true) { if(num++ == 30) { //num为30后调用changeFlag方法改变标记值 sp.changeFlag(); break; } System.out.println(Thread.currentThread().getName() + "....." + num); } } } class StopThreadDemo implements Runnable { //设置循环运行标记值 private boolean flag = true; @Override public void run() { while(flag) { //打印当然运行的线程名字 System.out.println(Thread.currentThread().getName() + "....run"); } } //改变标记值为false public void changeFlag() { flag = false; } }
停止方法2:使用interrupt()方法。结束线程的冻结状态(sleep、wait、join方法),使线程回到运行状态中来。也就是靠异常机制来结束线程。
package com.sergio.thread; /** * 打断线程冻结状态:当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。 * 强制让线程恢复到运行状态中来。改变标记让线程运行 * Created by Sergio on 2015/1/5. */ public class StopThreadDemo2 { public static void main(String[] args) { StopThread2 sp = new StopThread2(); Thread t1 = new Thread(sp); Thread t2 = new Thread(sp); t1.start(); t2.start(); //计数基数 int num = 0; while (true) { if (num++ == 60) { //打断t1、t2线程的冻结状态,让线程恢复到运行状态 t1.interrupt(); t2.interrupt(); break; } System.out.println(Thread.currentThread().getName() + "....." + num); } } } class StopThread2 implements Runnable { private boolean flag = true; @Override public synchronized void run() { while (flag) { try { //冻结状态 wait(); } catch (InterruptedException e) { //异常处理方法 System.out.println(Thread.currentThread().getName() + "中断异常"); flag = false; } System.out.println(Thread.currentThread().getName() + "...run"); } } }
守护线程
线程分类为:用户线程和守护线程。守护线程可以理解为后台线程,我们看到的都是用户线程。守护线程开启后,同用户线程共同抢夺cpu执行权。只是在结束时不一样,守护线程在所有用户线程结束后,会自动结束。像是守护依赖于用户线程。比如说:输入动作线程结束后输出动作线程自动结束。java的垃圾回收器。语法:
setDaemon(boolean b)。true为开启。
注意:该方法必须在启动线程前调用。
join方法
也就是抢夺cpu的执行权。可以用来临时加入线程执行。
特点:当a线程执行到了b线程的join方法,a就会等待,等b线程都执行完,a才会从冻结状态恢复到运行状态执行。
语法:
t1.join();
线程优先级
目前CPU使用权争夺有两种调度模型:分时调度模型和抢占式调度模型,Java 使用抢占式调度模型。
分时调度模型:所有线程轮流使用CPU 的使用权,平均分配每个线程占用CPU 的时间片
抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU 时间片相对多一些。
线程优先级为了:MAX_PRIORITY(最高级为10),MIN_PRIORITY(最低级为1),NORM_PRIORITY(默认及为5)。优先级为:1-10。优先级高的线程只能说明能抢占的cpu执行权较多些,执行的时间较多些。
线程启动后不能再次设置优先级。必须在线程启动前设置优先级。
package com.sergio.thread; /** * 设置线程优先级 * Created by Sergio on 2015/1/5. */ public class ThreadPriorityDemo { public static void main(String[] args) { ThreadPriority tp = new ThreadPriority(); Thread t1 = new Thread(tp, "t1"); Thread t2 = new Thread(tp, "t2"); //设置t1线程为10等级 t1.setPriority(Thread.MAX_PRIORITY); t1.start(); //设置线程t2为1等级 t2.setPriority(Thread.MIN_PRIORITY); t2.start(); } } class ThreadPriority implements Runnable { public void run() { for(int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + ",,," + i); } } }
yield方法
跟sleep方法类似,只是不能由用户指定暂停多长时间,减缓线程的运行频率,并且yield方法只能让同优先级的线程有执行机会。class ThreadPriority implements Runnable { public void run() { for(int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + ",,," + i); if(i % 10 == 0) { System.out.println("--------"); //暂停当前正在执行的线程,并执行其他同等优先级的线程 //当i为能被10整除时,该线程就会把CPU时间让掉,让其他或者自己的线程执行 Thread.yield(); } } } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统