内容概要:
1. 线程间通信的示例代码
2. 安全问题的解决
3. 等待唤醒机制
4. 代码优化
5. 生产者消费者例子
6. 生产者消费者例子代码优化(JDK5.0升级版)
1.线程间通信
线程间通信,其实就是多个线程在操作同一个资源,但是操作的动作不同。
class Res
{
String name;
String sex;
}
class Input implements Runnable
{
int x = 0;
private Res r;
public Input(Res r)
{
this.r = r;
}
public void run()
{
while (true)
{
if (x==0)
{
r.name = "mike";
r.sex = "man";
}
else
{
r.name = "丽丽";
r.sex = "女女女女女女";
}
x= (x+1)%2;
}
}
}
class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while (true)
{
System.out.println(r.name+"++++++"+r.sex);
}
}
}
class InputOutputDemo
{
public static void main(String[] args)
{
Res r = new Res();
Input i = new Input(r);
Output o = new Output(r);
Thread t1 = new Thread(i);
Thread t2 = new Thread(o);
t1.start();
t2.start();
}
}
可以发现,运行输出出现了错误的情况。
2.安全问题的解决
在上边的示例代码运行后,发现有输出错误这样的安全问题,这里需要去解决。
通过分析发现,这种错误的产生来源是,多线程运行的时候,交叉取得CPU权限时中断的随机性导致。
解决的思路:
1). 考虑是否多线程
2). 是否使用同一把锁
更改后代码
class Res
{
String name;
String sex;
}
class Input implements Runnable
{
private Res r;
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
synchronized(r)//同步对象的选用
{
if (x==0)
{
r.name ="mike";
r.sex = "man";
}
else
{
r.name = "丽丽";
r.sex = "女女女女女女";
}
x = (x+1)%2;
}
}
}
}
class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while (true)
{
synchronized(r)//同步对象的选用
{
System.out.println(r.name+"++++++"+r.sex);
}
}
}
}
class InputOutputDemo
{
public static void main(String[] args)
{
Res r = new Res();
Input i = new Input(r);
Output o = new Output(r);
Thread t1 = new Thread(i);
Thread t2 = new Thread(o);
t1.start();
t2.start();
}
}
运行发现,修改后的代码输出无错误,但是出现了大片连续的相同输出。
3.等待唤醒机制
鉴于前述解决了安全问题后,多线程运行不够理想——非交替运行状态。
那么要实现交替运行该如何办呢?
这里要用到wait和notify方法。wait() notify() notifyAll() 以上几个方法,都是用在同步中的,我们要对持有监视器(锁)的线程操作,便要用到以上的方法。 只有同步才具有锁。 为什么这些操作线程的方法要定义Object类中嗯?
因为这些方法在操作同步中线程时,都必须要标示他们所操作线程只有的锁,
只有同一个锁上的被等待的线程,可以被同一个锁上的notify唤醒。
不可以对不同锁中的线程进行唤醒,也就是,等待和唤醒必须是同一个锁
而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
class Res
{
String name;
String sex;
boolean flag = true;
}
class Input implements Runnable
{
private Res r;
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
synchronized(r)//同步对象的选用
{
if (r.flag)
try{r.wait();} catch (Exception e){}
if (x==0)
{
r.name ="mike";
r.sex = "man";
}
else
{
r.name = "丽丽";
r.sex = "女女女女女女";
}
x = (x+1)%2;
r.flag = true;
r.notify();
}
}
}
}
class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while (true)
{
synchronized(r)//同步对象的选用
{
if (!r.flag)
try{r.wait();} catch (Exception e){}
System.out.println(r.name+"++++++"+r.sex);
r.flag = false;
r.notify();
}
}
}
}
class waitnotifyDemo
{
public static void main(String[] args)
{
Res r = new Res();
Input i = new Input(r);
Output o = new Output(r);
Thread t1 = new Thread(i);
Thread t2 = new Thread(o);
t1.start();
t2.start();
}
}
运行输出如图,代码加入等待唤醒机制后,实现了线程交替运行的目的。
4.代码优化
代码优化:
方向:数据私有化,提供访问方法。
class Res
{
private String name; //应当私有化
private String sex;
private boolean flag = false;
public synchronized void set(String name,String sex)//提供数据访问方法
{
if (flag)
try{wait();} catch (Exception e){}
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
public synchronized void out()//提供数据访问方法
{
if (!flag)
try{wait();} catch (Exception e){}
System.out.println(name+"++++++"+sex);
flag = false;
this.notify();
}
}
class Input implements Runnable
{
private Res r;
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
if (x==0)
r.set("mike","man");
else
r.set("丽丽","女女女女女女");
x= (x+1)%2;
}
}
}
class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while (true)
{
r.out();
}
}
}
class IODemo1
{
public static void main(String[] args)
{
Res r = new Res();
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
Input i = new Input(r);
Output o = new Output(r);
Thread t1 = new Thread(i);
Thread t2 = new Thread(o);
t1.start();
t2.start();
}
}
- 5.生产者消费者例子
当有多个生产者,多个消费者时,必须循环判断标记,避免生产多个,消费一个,或者生产一个,消费多次等情况出现
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name)
{
while (flag)
{
try
{
wait();
}
catch (Exception e)
{
}
}
this.name = name+" "+count++;
System.out.println(Thread.currentThread().getName()+"<++++++生产者+.."+this.name);
flag = true;
notifyAll();
}
public synchronized void get()
{
while (!flag)
{
try
{
wait();
}
catch (Exception e)
{
}
}
System.out.println(Thread.currentThread().getName()+"------>消费者-"+name);
flag = false;
notifyAll();
}
}
class Producer implements Runnable
{
private Resource r;
public Producer(Resource r)
{
this.r = r;
}
public void run()
{
while (true)
{
r.set("product");
}
}
}
class Consumer implements Runnable
{
private Resource r;
public Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while (true)
{
r.get();
}
}
}
class ProducerConsumerDemo
{
public static void main(String[] args)
{
Resource r = new Resource();
Producer p = new Producer(r);
Consumer c = new Consumer(r);
Thread t1 = new Thread(p);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
- 6.生产者消费者例子代码优化(JDK5.0升级版)