线程间的协作:
首先看一个例程:要实现显示时间的功能,但是由于线程的抢占原因,所以不一定可以输出时间!
package keeper;
import java.util.Date;
public class Test {
private static String time;
static class display extends Thread{
Time timeThread;
display(Time time){
this.timeThread=time;
}
@Override
public void run() {
System.out.println(time);
}
}
static class Time extends Thread{
@Override
public void run() {
time=new Date().toString();
}
}
public static void main(String[] args) {
Time timeThread =new Time(object);
timeThread.start();
new display(timeThread,object).start();
}
}
接下来进行改造:
在display线程中设置阻塞,sleep();
在display线程中加入时间线程,join();
实现结果如下
package keeper;
import java.util.Date;
public class Test {
private static String time;
static class display extends Thread{
Time timeThread;
display(Time time){
this.timeThread=time;
this.object=object;
}
@Override
public void run() {
if(time==null) {
try {
timeThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(time);
}
}
static class Time extends Thread{
@Override
public void run() {
time=new Date().toString();
}
}
public static void main(String[] args) {
Object object =new Object();
Time timeThread =new Time();
timeThread.start();
new display(timeThread).start();
}
}
实验结果如下:
这种情况可以输出时间。这就是简单的线程之间的协作
下面使用wait()、notify()和notifyAll()三个方法解决了线程间的协作问题,解决线程的先后顺序。
线程协作:
synchronized关键字只是起到了多个线程“串行”执行临界区中代码的作用,但是哪个线程先执行,哪个线程后执行依无法确定,Object类中的wait()、notify()和notifyAll()三个方法解决了线程间的协作问题,通过这三个方法的“合理”使用可以确定多线程中线程的先后执行顺序:
1.wait():对象锁调用了wait()方法会使当前持有该对象锁的线程处于线程等待状态同时该线程释放对对象锁的控制权,直到在其他线程中该对象锁调用notify()方法或notifyAll()方法时等待此对象锁的线程才会被唤醒。
2.notify():对象锁调用notify()方法就会唤醒在此对象锁上等待的单个线程。
3.notifyAll():对象锁调用notifyAll()方法就会唤醒在此对象锁上等待的所有线程;调用notifyAll()方法并不会立即激活某个等待线程,它只能撤销等待线程的中断状态,这样它们就能够在当前线程退出同步方法或同步代码块法后与其它线程展开竞争,以争取获得资源对象来执行。
•一句话:谁调用了wait方法,谁就必须调用notify或notifyAll方法,并且“谁”是对象锁。
这里例程奉上:
package keeper;
import java.util.Date;
public class Test {
private static String time;
static class display extends Thread{
Object object;
Time timeThread;
display(Time time,Object object){
this.timeThread=time;
this.object=object;
}
@Override
public void run() {
if(time==null) {
synchronized (object) {
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(time);
}
}
static class Time extends Thread{
Object object;
Time(Object object){
this.object=object;
}
@Override
public void run() {
time=new Date().toString();
synchronized (object) {
object.notify();
}
}
}
public static void main(String[] args) {
Object object =new Object();
Time timeThread =new Time(object);
timeThread.start();
new display(timeThread,object).start();
}
}
这个可以完美解决线程之间的协作,以及先后问题。
sleep()方法和wait()方法区别:
- sleep()方法被调用后当前线程进入阻塞状态,但是当前线程仍然持有对象锁,在当前线程sleep期间,其它线程无法执行sleep方法所在临界区中的代码。
- 对象锁调用了wait()方法会使当前持有该对象锁的线程处于线程等待状态同时该线程释放对对象锁的控制权,在当前线程处于线程等待期间,其它线程可以执行wait方法所在临界区中的代码。
下面还会奉上几个例程,供大家继续解读探究。
例程一:
尽管while循环是死循环,但由于对象锁lockObj调用了wait()方法,使得分别持有该lockObj对象锁的“1号计数器”线程和“2号计数器”线程处于线程等待状态,所以循环并没有继续下去
class CounterThread extends Thread {
private Object lockObj;
public CounterThread(String threadName, Object lockObj) {
super(threadName);
this.lockObj = lockObj;
}
@Override
public void run() {
int i = 1;
while (true) {
synchronized (lockObj) {
System.out.println(getName() + ":" + i);
try {
lockObj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
}
}
}
public class Test {
public static void main(String[] args) {
Object lockObj = new Object();
new CounterThread("1号计数器",lockObj).start();
new CounterThread("2号计数器",lockObj).start();
}
}
例程二:
尽管whlie循环是死循环, “1号计数器”线程和“2号计数器”线程输出1后对象锁lockObj调用了wait()方法,使得两个线程进入线程等待状态;但主线程在sleep 5000毫秒后启动了NotifyAllThread线程类创建的线程对象,该线程对象在执行run方法时对象锁调用了notifyAll方法,致使两个线程全部被唤醒,所以两个线程又循环了一遍
class CounterThread extends Thread {
private Object lockObj;
public CounterThread(String threadName, Object lockObj) {
super(threadName);
this.lockObj = lockObj;
}
@Override
public void run() {
int i = 1;
while (true) {
synchronized (lockObj) {
System.out.println(getName() + ":" + i);
try {
lockObj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
}
}
}
class NotifyAllThread extends Thread {
private Object lockObj;
public NotifyAllThread(Object lockObj) {
this.lockObj = lockObj;
}
@Override
public void run() {
synchronized (lockObj) {
System.out.println("notifyAll方法执行完毕");
lockObj.notifyAll();
}
}
}
public class Test {
public static void main(String[] args) {
Object lockObj = new Object();
new CounterThread("1号计数器", lockObj).start();
new CounterThread("2号计数器", lockObj).start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new NotifyAllThread(lockObj).start();
}
}