一,Suspend():挂起,不抢占CPU了,相当于阻塞了 ----- 被wait替代
Resume():唤醒 ,重新抢占CPU----- 被notify替代
运行结果:先输出1,然后回车唤醒一次,输出一次,直到输出完毕
注意: Suspend(),resume()这两个方法过时,并且禁止使用。
Suspend()挂起的线程不安全,而且容易出现死锁,一旦挂起,不会释放锁
二, Join():加入,当一个线程从中间加入进来后就会独享cpu,会把自己所有的代码执行完毕之后才让出cpu让其他线程执行
package 多线程;
import java.io.IOException;
class A implements Runnable{
private Thread b;//A关联B获得B的线程
public A(Thread b){//构造器调用B的构造器
this.b=b;
}
int i;
public void run() {
for (i = 1; i <=10; i++) {
if(i==3){//当A输出到3的时候,B加进来,一口气输出完
try {
b.join();//此处的异常只能捕获,因为join的父类的异常没有抛
//所以子类也不能抛
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
class B implements Runnable{
public void run() {
for (int i = 1; i <=10; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
public class Test {
public static void main(String[] args) throws IOException {
//新建状态
B b=new B();
Thread t2=new Thread(b,"我是b,我加入进来");
A a=new A(t2);
Thread t1=new Thread(a,"我是a");
//运行状态
t1.start();
t2.start();
}
}
运行结果为:
join的另一个应用:如下图:当我们以为只有一条线程时,就忽略了main也是一条线程,原本会输出8,但是当18代表的线程加入进来后,不管它睡眠多久,8也得等着。
三,Sleep():睡眠
见上一篇
四,yield():让步,针对同一级别的其它线程,当前线程会让出cpu再和其它同一级别的线程重新抢占cpu。注意是让出之后再重新抢,不是让给它,只是给了它一次抢占CPU的机会。
上程序的意思是:不管是谁输出一次,让出CPU重新抢,结果如下:
五,线程的同步,协调
同步就是线程安全,就是保证任务块里面的所有代码是一个原子性,不可分割!不能只输出到一半就让其他代码抢走线程,从而导致数据不安全
每一个对象都是一把锁,这个锁在同一时刻只能被其中一个线程所具有,如果多个线程竞争同一把锁,那么就要等待
比如这个程序:上了锁之后即使A的线程被B抢走,B也不能立即执行,而是等到A把它里面的程序输出完整后,释放锁。B拿到锁后执行程序,同时上锁,如若A再抢到线程,也要等到B程序输出完整后才可以执行
就像这样,不可能说执行到中间让其他程序抢走线程后就直接中断,而是会完整输出,在释放锁,让其他程序执行。前提是两个程序要用同一把锁,如果不上锁或者上两把锁,输出也不会完整,数据也不安全。
package 多线程;
import java.io.IOException;
class A implements Runnable{
Object lock;
public A(Object lock){
this.lock=lock;
}
public void run() {
while(true){
//上锁
synchronized (lock) {
System.out.println("1111111111111");
System.out.println("2222222222222");
System.out.println("3333333333333");
System.out.println("4444444444444");
}
//释放锁
}
}
}
class B implements Runnable{
Object lock;
public B(Object lock){
this.lock=lock;
}
public void run() {
//加同步块,锁lock对象
while(true){
synchronized (lock) {
System.out.println("aaaaaaaaaaaaaaaaaa");
System.out.println("bbbbbbbbbbbbbbbbbb");
System.out.println("cccccccccccccccccc");
System.out.println("dddddddddddddddddd");
}
//释放锁
}
}
}
public class Test {
public static void main(String[] args) throws IOException, InterruptedException {
Object obj=new Object();
A a=new A(obj);
B b=new B(obj);
Thread t1=new Thread(a);
Thread t2=new Thread(b);
t1.start();
t2.start();
}
}
以上就是现场的同步,确保了线程的安全性。
协调,在同步的基础上协调工作,就好比走路,不管是先迈出左脚还是右脚,总之走路要一左一右,才是协调。
如下图,在锁里加入obj.wait(),表示输出完了之后等待。
此时出现的异常要捕获,以为他的父类没有抛异常
如果两条线程都加了obj.wait;则会有下面的结果:
两个线程各输出一次,然后等待,但是程序依然没有结束。所以为了让线程继续下去,我们需要在等待之前唤醒对方线程。
注意:不能写成这样,如果这样,在线程等待的时候,不能执行后面的程序,所以也就不能唤醒对方线程,要把obj.notify写在obj.wait的前面。
obj.wait();
obj.notify();
所以代码如下:
class AA implements Runnable{
Object obj;
public AA(Object obj){
this.obj=obj;
}
public void run() {
while(true){
synchronized (obj) {
System.out.println("AAAAA");
System.out.println("BBBBB");
System.out.println("CCCCC");
System.out.println("DDDDD");
try {
//唤醒正在等待的对方线程
obj.notify();
//该线程处于等待状态,不抢占cpu,同时释放锁
obj.wait();//异常捕获,因为父类没有抛异常
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}}
class BB implements Runnable{
Object obj;
public BB(Object obj){
this.obj=obj;
}
public void run() {
while(true){
synchronized (obj) {
System.out.println("11111");
System.out.println("22222");
System.out.println("33333");
System.out.println("44444");
try {
obj.notify();
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}}
public class Test {
public static void main(String[] args) {
Object obj=new Object();
AA a=new AA(obj);
BB b=new BB(obj);
Thread t1=new Thread(a);
Thread t2=new Thread(b);
t1.start();
t2.start();
}
}
输出结果: