接着上一篇继续看,这篇主要讲线程之间的通信,如果没看之前的请点击多线程详解,线程的同步,先看几个方法:
- wait()与notify()和notifyAll()
- wait():当前线程挂起并放弃CPU、同步资源,让别的线程可以访问并修改共享资源,而当前线程排队等候再次对资源访问。
- notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待。
- notifyAll():唤醒正在排队等待资源的所有线程结束等待。
- Java.lang.Object提供的这三个方法只有在
synchronized
方法或synchronized
代码块中才能使用,否则会报java.lang.IllegalMonitorStateException
异常。
方法的运用,2个线程交互打印到100
class SubThread implements Runnable{
int number=1;
public void run(){
while (true){
synchronized(this){
notify();//当线程挂起的时候,需要唤醒
if(number<=100){
try{
Thread.currentThread().sleep(1000);
}catch (Exception e){
}
System.out.print(number);
number++;
}else{
break;
}
try{
wait();
}catch (Exception e){
}
}
}
}
}
class TestThread{
public static void main(String []args){
SubThread st=new SubThread();
Thread th1=new Thread(st);
Thread th2=new Thread(st);
th1.setName("甲");
th2.setName("乙");
th1.start();
th2.start();
}
}
经典例题,消费者与生产者
生产者(productor)将产品交给店员(clerk),而消费者(Customer)从店员取走,店员一次只有有固定数量的产品20个,如果生产者生产大于20个,店员会叫生产者停一下,如果店里有空位放产品再通知生产者生产,如果店中没产品,店员会告诉消费者等一下,有产品再叫消费者来取走产品。
分析例题:
- 是否涉及多线程问题?是,消费者和生产者。
- 是否涉及到共享数据?有,产品的固定数量。
- 是否涉及到线程的通信? 是,消费者和生产者之间通信。
class Clerk{
int number;
public synchronized void addProduct(){//锁为this,Clerk对象
if(number>=20){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
number++;
notifyAll();
}
}
public synchronized void cutProduct(){//锁为this,Clerk对象
if(number<=0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
number--;
notifyAll();
}
}
}
//生产者
class Productor implements Runnable{
Clerk clerk;
public Productor (Clerk clerk){
this.clerk=clerk;
}
@Override
public void run() {
System.out.print("生产者生产产品");
while (true){
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.addProduct();
}
}
}
//消费者
class Customer implements Runnable{
Clerk clerk;
public Customer (Clerk clerk){
this.clerk=clerk;
}
@Override
public void run() {
System.out.print("消费者消费产品");
while (true){
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.cutProduct();
}
}
}
class TestThread{
public static void main(String [] agrs){
Clerk clerk=new Clerk();
Productor pc=new Productor(clerk);
Customer cm=new Customer(clerk);
Thread t1=new Thread(pc); //生产者线程
Thread t3=new Thread(pc);//生产者线程
Thread t2=new Thread(cm);//消费者线程
t1.setName("生产者");
t3.setName("生产者2");
t2.setName("消费者");
t1.start();
t2.start();
t3.start();
}
}
常见疑难解答:
java中线程与线程之间怎么通信。
不同线程共享一个变量,并对该变量的访问进行同步操作,因为他们共享一个内存空间,所以相比之下,它比进程之间要简单。
什么是进程的死锁和饥饿。
饥饿:当一个进程永久性的占有资源,使得其他进程得不到该资源,就发生了饥饿。死锁:当2个线程都需要对方的资源时,但因为某种原因都得不到资源,就僵持不下,这样就出现了死锁。
多线程的死锁问题。
避免使用suspend()和resume()方法,这些方法与生俱来就产生死锁的缺点。不要对长时间I/O操作的方法施加锁。 使用多个锁是,确保所有线程都按相同的顺序获得锁。