线程常见的方法:sleep、yield、join、wait、notify、notifyAll、interrupt、setPriority
yield:暂停执行当前线程,并执行其他线程(相同优先级线程更有机会运行)
sleep:休眠,可以让调用它的线程沉睡(停止运行)指定的时间,到了这个时间,线程就会自动醒来,变为可运行状态(RUNNABLE),但这并不表示它马上就会被运行,因为线程调度机制恢复线程的运行也需要时间。调用sleep()方法并不会让线程释放它所持有的同步锁;而且在这期间它也不会阻碍其它线程的运行。上面的连个方法都声明抛出一个InterruptedException类型的异常,这是因为线程在sleep()期间,有可能被持有它的引用的其它线程调用它的interrupt()方法而中断。中断一个线程会导致一个InterruptedException异常的产生,如果你的程序不捕获这个异常,线程就会异常终止,进入终止状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。
Thread t = new Thread(){
@Override
public void run() {
try {
System.out.print("11");
sleep(3000);
System.out.print("22");
}catch(InterruptedException e) {
System.out.print("33");
}
}
};
t.start();
t.interrupt();
这里 如果没有t.interrupt()执行 就打印出1122,如果有执行,就为1133。
join:当前线程停止执行,知道join的这个线程执行完成为止,如果它所加入的线程没有存活,则当前线程无需停止,jion(5000)让当前线程等待5s,超时
停止等待,变为可运行
wait:让线程等待(这里要注意与sleep的区别:不改变对象的机锁,即在synchronized中调用sleep,其他线程不能使用,而wait可以)
interrupt:一般不会中断正在执行的线程,只会对wait、join、sleep方法阻塞的线程中断
synchronized:同步锁,应避免在同步中使用sleep和yield方法,这样cpu资源就无法释放,其他进程就不能执行。每个对象都有一个锁与之对应,它是作用
在对象在堆中的地址上,所有在栈上内容就无法加锁,如对象的引用、基本类型。
notify、notifyAll、wait:这三个是基于Object类,所有 所有对象都有这三个方法。
这里说下notify和notifyAll:
我们在synchronized同步锁的时候,如果有一个线程来执行,就会获取这个锁的一个通行证,如果在它还未执行完归还通行证的时候,有其他线程来执行,那
最新来的那些线程就会形成一个等待队列,称为schedule,当我们拥有通行证的那个线程执行完毕归还通行证,通过拥有通行证的这个对象notify,会唤醒一个线程,
具体是哪个线程由jvm来决定,notifyAll就是唤醒所有线程。
学习了上面的内容,我们可以通过下面几个题目来练习下:
1.有三个线程ID分别是A、B、C,请有多线编程实现,在屏幕上循环打印10次ABCABC
public class ThreadDemo {
/**
* 这里是利用同步对象来实现三个线程循环打印ABC
*/
/**
* 先定义一个单例对象锁
*/
static class DemoLock {
private static DemoLock mDemoLock = null;
private char charactor = 'A';
public static DemoLock getInstance() {
if (mDemoLock == null) {
mDemoLock = new DemoLock();
}
return mDemoLock;
}
public void setCharactor() {
this.charactor += 1;
if (this.charactor == 'D') {
this.charactor = 'A';
}
}
public char getCharactor() {
return this.charactor;
}
}
static class DemoRunnable implements Runnable {
private DemoLock mDemoLock;
private char mChar = ' ';
public DemoRunnable(DemoLock lock, char charactor) {
this.mDemoLock = lock;
this.mChar = charactor;
}
@Override
public void run() {
//定义一个循环遍历
int i = 0;
while(i < 10) {
synchronized(mDemoLock) {
//这里我们第一个的mDemoLock.getCharactor肯定是A,然后如果不是A线程,那就wait
//直到A线程执行完后继续,setCharactor完后是B,只有等B线程循环完后才继续,一直循环
while(this.mChar != mDemoLock.getCharactor()) {
try {
mDemoLock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//打印出这个值
System.out.println(this.mChar);
i++;
mDemoLock.setCharactor();
mDemoLock.notifyAll();
}
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
DemoLock mLock = DemoLock.getInstance();
Thread mThreadA = new Thread(new DemoRunnable(mLock, 'A'));
Thread mThreadB = new Thread(new DemoRunnable(mLock, 'B'));
Thread mThreadC = new Thread(new DemoRunnable(mLock, 'C'));
mThreadA.start();
mThreadB.start();
mThreadC.start();
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
Thread_E tc = new Thread_E();
Thread_E tb = new Thread_E();
Thread_A ta = new Thread_A();
ta.setThread(tb);
tb.setThread(tc);
tc.setThread(ta);
ta.setName("A");
tb.setName("B");
tc.setName("C");
tb.start();
tc.start();
ta.start();
}
}
/**这里我们简单介绍下实现方法:
* Thread_A先打印当前线程的名字吗,然后通过this.join等待直到被中断唤醒,并对中断t线程
* Thread_E先通过this.join等待直到被中断唤醒,然后打印当前线程名称并中断t线程
* 这样我们通过mian里面的代码可以看到:如果A线程先执行,那就打印出A线程名称,则等待,然后中断B线程
* ,B线程执行,则等待,直到A线程执行完中断B线程,它会被唤醒,打印B线程名称并中断C线程
* C线程执行,则等待,直到B线程执行完中断C线程,它会被唤醒,打印B线程名称并中断A线程
* 这样就形成了一个循环
*/
class Thread_A extends Thread {
Thread t;
public void setThread(Thread t) {
this.t = t;
}
public void run() {
int i = 0;
while(i++ < 10) {
System.out.print(Thread.currentThread().getName());
t.interrupt();
try {
//这里会一直等待,直到当前线程被中断才会继续执行
this.join();
} catch (InterruptedException e) {
}
}
}
}
class Thread_E extends Thread {
Thread t;
public void setThread(Thread t) {
this.t = t;
}
public void run() {
int i = 0;
while(i++ < 10) {
try {
//这里会一直等待,直到当前线程被中断才会继续执行
this.join();
} catch (InterruptedException e) {
}
System.out.print(Thread.currentThread().getName());
t.interrupt();
}
}
}
2.多线程实现1+...100