首先先看一段小例子:
描述这样一个场景:
多线程问题就被简化为一个资源库,有的线程往里添加资源,有的线程往外输出资源。
描述该部分的代码示例:
/*
*线程间通讯问题
*其实就是多线程操作同一个资源
*但是操作的动作不同
*/
class Res
{
String name; //定义一个资源库 由Input往里面添加资源,Output往外面出售资源
String sex;
}
class Input implements Runnable
{
private Res r;
Input(Res r) //初始化一个资源库
{
this.r=r;
}
public void run()
{
int n=0;
while(true)
{
if(n==0)
{
r.name="mike"; //插入资源
r.sex="man";
}
else{
r.name="丽丽";
r.sex="女";
}
n=(n+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 test
{
public static void main(String[] args)
{
//System.out.println("Hello World!");
Res r=new Res();
Input in=new Input(r);
Output out=new Output(r);
Thread t1=new Thread(in);
Thread t2=new Thread(out);
t1.start();
t2.start(); //资源的启动
}
}
运行结果截图:
先不说while是个死循环,那是为了看到运行结果写的。该多线程描述就是对于一个资源库进行存资源,取资源的过程。出现问题的原因就是线程权限抢过来抢过去的问题,当存获取到权限刚执行完mike后还没来得及存man就被输出抢走占据cpu的权限。
解决方法:
用同步线程锁。
再看完善后的代码:
/*
*线程间通讯问题
*其实就是多线程操作同一个资源
*但是操作的动作不同
*/
/*
* wait()
* notify()
* notifyAll()
* 都是用在同步中,因为要对持有监视器(锁)的线程的操作
* 因为只有同步才具有锁
* 为什么这些操作线程的方法要定义Object类中呢?
* 因为这些方法在操作同步线程时,都必须标示他们操作线程只有的锁
* 只有同一个锁上的被等待线程,才能被同一个锁上的notify()唤醒,不可以对不同锁上的唤醒
*
* 也就是说等待唤醒必须同一个锁,而锁可以是任意对象,所以可以被任意对象调用的定义方法Object类中。
*
*
*/
class Res
{
private String name; //定义一个资源库 由Input往里面添加资源,Output往外面出售资源
private String sex;
private boolean flag=false;
public synchronized void set(String name,String sex)
{
if(flag)
try{
this.wait(); //执行就放弃了执行的资格
}catch (Exception e) {
// TODO: handle exception
}
this.name=name;
this.sex=sex;
flag=true;
this.notify();//唤醒该对象正在等待该对象的线程
}
public synchronized void out()
{
if(!flag)
try{
this.wait(); //执行就放弃了执行的资格
}catch (Exception e) {
// TODO: handle exception
}
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 n=0,m=0;
while(m<100)
{
if(n==0)
{
r.set("mike","man");//插入资源
}
else{
r.set("丽丽","女");
}
n=(n+1)%2;
m++;
}
}
}
class Output implements Runnable
{
private Res r;
Output(Res r) //初始化资源
{
this.r=r;
}
public void run()
{
int i=0;
while (i<100)
{
r.out();//调用out输出资源
i++;
}
}
}
class test
{
public static void main(String[] args)
{
//System.out.println("Hello World!");
Res r=new Res();
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
/*
Input in=new Input(r);
Output out=new Output(r);
Thread t1=new Thread(in);
Thread t2=new Thread(out);
t1.start();//启动线程
t2.start();
*/
}
}
输出结果:
心得:
Synchronized是对当前的实例进行加锁,要注意是“当前实例”,也就是说,假如你有两个实例化对象,那么可以同时访问这两个实例里面的Synchronized块。但是,当访问一个实例里面的一个Synchronized块时,其余的synchronized是不可同时访问的,原因是整个实例都被加了锁。
另外注意wait()和notify():如果条件不满足,则等待。当条件满足时,等待该条件的线程将被唤醒。一般用在synchronized机制中,用在一个对象中,描述对一个对象的控制。