Java线程间通信简单来说就是多个线程同时操作同一个资源,比如一个线程设置了姓名、性别,另一个线程读取姓名、性别。
伴随而来的就是同步问题:比如线程a先设置了张三、男,后设置了李四、女,线程b要打印这些信息,由于多线程的随机性,a设置张三、男后,然后a又设置了李四,还未设置性别时,b这时候读取数据,独到的就是李四、男,这样结果就不对了。解决方法就是加锁,保证a在赋值时,b没有读取;b读取时,a没有在赋值。
wait:java.lang.Object.wait(),java api是这么解释的:当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,
直到其他线程通过调用notify
方法,或 notifyAll
方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新
获得对监视器的所有权后才能继续执行。
notify:唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。
选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个wait
方法,在对象的监视器上等待。
很难懂吧,简单来说就是让持有当前锁对象的线程等待或启动。
wait 和 notify
都是用在同步中,因为要对持有监视器(锁)的线程操作,所以要是用在同步中,只有同步才具有锁。
为什么操作线程的方法要定义在Object类中?
因为这些方法在操作同步线程时,都必须要表示他们所操作线程持有的锁。只有同一个锁上的被等待线程可以被同一个锁上的notify唤醒,不可以对不同锁中的线程进行唤醒。
等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。
package threaddemo.deadthread;
import java.io.ObjectInputStream.GetField;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
/**
* 多线程通信
*
* @author JYF
*
*/
public class ThreadCommunicateClient {
public static void main(String[] args) {
PropertyConfigurator.configure("src/log4j.properties");
User user = new User();
Generator generator = new Generator(user);
Consumer consumer = new Consumer(user);
Thread createThread = new Thread(generator, "generator.thread");
Thread consumerTherad = new Thread(consumer, "consumer.thread");
createThread.start();
consumerTherad.start();
}
}
class User {
private String name;
private String sex;
private boolean isWriten = false;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isWriten() {
return isWriten;
}
public void setWriten(boolean isWriten) {
this.isWriten = isWriten;
}
}
/**
* \ 生成用户信息
*
* @author JYF
*
*/
class Generator implements Runnable {
User user;
Logger log = Logger.getLogger(getClass());
Generator(User user) {
this.user = user;
}
@Override
public void run() {
int i = 0;
while (true) {
synchronized (user) {
if (!user.isWriten()) {
if (i % 2 == 0) {
user.setName("张三");
user.setSex("男");
user.setWriten(true);
} else {
user.setName("李四");
user.setSex("女");
user.setWriten(true);
}
i = i + 1;
user.notify();
}
else {
try {
user.wait();
} catch (InterruptedException e) {
log.error("");
}
}
}
}
}
}
/**
* 消费用户信息
*
* @author JYF
*
*/
class Consumer implements Runnable {
User user;
Logger log = Logger.getLogger(getClass());
Consumer(User user) {
this.user = user;
}
@Override
public void run() {
while (true) {
synchronized (user) {
if (user.isWriten()) {
log.info(user.getName() + " " + user.getSex());
user.setWriten(false);
user.notify();
}
else {
try {
user.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
参考:java api,毕向东老师多线程相关视频