多线程浅析(二)
JAVA中多线程是抢占式的运行方式,哪个线程抢占到时间片,哪个线程就先运行。而线程调度是按照某种原则选择一个线程使它占有处理器运行,线程调度是操作系统的核心,线程调度策略的优劣直接影响操作系统的性能。线程调度有相对调度和绝对调度。
1.相对调度
(1)Thread.setPriority()设置线程优先级—线程优先级有10级,越大越优先(优先级越高只是说该线程抢占的资源的几率会更大,并不绝对)
(2)Thread.sleep()让当前线程睡眠一段时间—对当前线程操作,是静态方法,除非被中断而提前恢复执行,否则线程在这段时间不会执行
注意:在引入同步锁时,sleep()方法不会释放锁,但会把处理器资源释放出来
(3)Thread.interrupt()—调用一个被暂停线程的interrupt()方法,可以变相起到唤醒暂停线程的作用,所以能够用来作为强制唤醒线程的技术
(4)Thread.yield()—放弃当前线程抢占到的机会,然后和其他同优先级的线程再抢一次(这里只是放弃当前的机会,有可能再抢一次的时候又是该线程抢到)
相对调度代码演示:
public class S`chedualDemo {
public static void main(String[] args) {
MyRun r1=new MyRun(1);
Thread t1=new Thread(r1);
MyRun r2=new MyRun(2);
Thread t2=new Thread(r2);
//1、相对调度
//设置线程优先级,优先级从1~10,越大越优先
t1.setPriority(10);
t2.setPriority(1);
t1.start();//启动线程
t2.start();//启动线程
try {
Thread.sleep(1000);//线程睡眠
t2.interrupt();//强制唤醒,当前线程会进入运行态--相对调度
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyRun implements Runnable{
private int num;
public MyRun(int num){
this.num=num;
}
@Override
public void run() {
if(num==1){
//这里Thread.sleep()让当前线程睡眠,但是但存在锁时,不会释放锁,只会把内存资源释放出去
//Thread.sleep(10);
Thread.yield();//相当于在同优先级的线程内部再抢一次
}
for(int i=0;i<10;i++){
//System.out.println(Thread.currentThread().getName()+":"+i);
//Thread.currentThread().getName()
System.out.println(num+":"+i);
}
}
}
2.绝对调度
(1)join()方法—调用某线程的该方法,把该线程与当前合并,即把当前线程运行结束,再恢复当前线程的运行。(相当于类中的调用方法)
(2)wait()方法—当前线程进入等待池中
(3)notify()或notifyAll()方法—唤醒等待池中一个或全部线程
注意:wait()和notify()方法必须对应使用;当线程拥有同步锁时,wait()方法既会释放处理器资源同时也会释放锁。
public class MyStack {
private char[] ch=new char[6];
private int idx=0;
//无论是锁方法还是同步块的锁,只要是同一把对象锁,都可以锁---效果是一样的
public void push(char c){
synchronized (this) {//拿锁
ch[idx]=c;
System.out.println("push:"+c);
idx++;
this.notify();
}//还锁
}
public synchronized char pop(){
if(idx==0){
try {
this.wait();//wait()方法会把锁释放出来,sleep()方法不会释放锁,但两者都会释放CPU资源
} catch (InterruptedException e) {
e.printStackTrace();
}
}
idx--;
System.out.println("pop:"+ch[idx]);
return ch[idx];
}
}
----------
public class PopThread extends Thread{
private MyStack ms=new MyStack();
public PopThread(MyStack ms){
this.ms=ms;
}
@Override
public void run() {
for(int i=97;i<103;i++){
ms.pop();
}
}
}
----------
public class PushThread extends Thread{
MyStack ms=new MyStack();
public PushThread(MyStack ms){
this.ms=ms;
}
@Override
public void run() {
for(int i=97;i<103;i++){
ms.push((char)i);
}
}
}
----------
public class Client {
public static void main(String[] args) {
MyStack ms=new MyStack();
Thread push=new PushThread(ms);
Thread pop=new PopThread(ms);
push.start();
pop.start();
}
}
3.线程相关概念
(1)线程的创建和线程的启动不相同:在一个线程对象没有调用start()方法时,这个线程对象并没有真正执行;而线程对象在启动之前或者退出之后都是存在的,都可以控制和获取线程的相关信息。
(2)线程的结束:
- 自然结束–达到run()方法的末尾
- 线程抛出一个未捕获到的Exception或Error
- 调用已经过时的stop()方法
(3)守护线程:在Java程序运行的时候,存在一些隐藏线程,这些线程随着程序启动而启动,在程序运行期间一直捕捉符合条件的处理