Java 线程二
使用多线程时出现的以下问题
代码如下:
class Resource //资源类
{
private String name;
private int count;
public boolean flag;
public synchronized void set(String name) {
if(flag) {
try {
this.wait(); //等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name+"..."+count++;
System.out.println(Thread.currentThread().getName()+ "生产者:" + this.name);
flag = true;
this.notify();//唤醒
}
public synchronized void out(){
if(!flag) {
try {
this.wait(); //等待
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+".....消费者:" + this.name );
flag = false;
this.notify(); //唤醒
}
}
class Producer implements Runnable{
private Resource res;
public Producer(Resource res) {
this.res = res;
}
@Override
public void run() {
while(true){
res.set("张三");
}
}
}
class Consumer implements Runnable{
private Resource res;
public Consumer(Resource res) {
this.res = res;
}
@Override
public void run() {
while(true){
res.out();
}
}
}
public class Demo2 {
public static void main(String[] args) {
Resource res = new Resource();
Producer pro = new Producer(res);
Consumer con = new Consumer(res);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
关于生产者与消费者的多线程,如果线程大于2个,则会出现不规则的情况,可能出现生产者生产一个商品,但消费了两次,或者生产者生产两个商品,只消费了一个商品等情况。
原因:
当存在多个线程时,生产者生产完成后会唤醒另外一个线程,但在线程池里面等待的有生产方和消费方,这时有可能唤醒的是生产方的线程,而唤醒的这个线程又没有去判断标记,这样的话就有可能出现生产次数与消费次数不一样的情况。
解决方案:
由于将被唤醒的线程并没有判断标记,所以可以将原 if 结构 改成 while 结构,这样每次被唤醒时都会去判断标记,但有可能出现线程全等待的情况,这是因为每次唤醒时只唤醒一个线程,而这个线程会判断标记,如果标记不通过则会被等待,这样的话,所有线程都处在等待状态,没有谁来唤醒谁, 解决办法就是因为每个线程在唤醒时都会判断标记,并且有锁,那么干脆把所有线程唤醒 notifyAll , 这样就解决问题了。
代码如下:
class Resource //资源类
{
private String name;
private int count;
public boolean flag;
public synchronized void set(String name) {
while(flag) { //每次唤醒时都会进行判断标记
try {
this.wait(); //等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name+"..."+count++;
System.out.println(Thread.currentThread().getName()+ "生产者:" + this.name);
flag = true;
this.notifyAll();//唤醒所有线程
}
public synchronized void out(){
while(!flag) { //每次唤醒时都会进行判断标记
try {
this.wait(); //等待
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+".....消费者:" + this.name );
flag = false;
this.notifyAll(); //唤醒所有线程
}
}
class Producer implements Runnable{
private Resource res;
public Producer(Resource res) {
this.res = res;
}
@Override
public void run() {
while(true){
res.set("张三");
}
}
}
class Consumer implements Runnable{
private Resource res;
public Consumer(Resource res) {
this.res = res;
}
@Override
public void run() {
while(true){
res.out();
}
}
}
public class Demo2 {
public static void main(String[] args) {
Resource res = new Resource();
Producer pro = new Producer(res);
Consumer con = new Consumer(res);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}