-----------android培训、java培训、java学习型技术博客、期待与您交流!------------
1、死锁
死锁产生的原因:一个所中还有另外一个锁,但是这两个锁对象是不相同的,其中一个锁(A)需要另外一个锁(B),而锁(B)也需要锁(A),这样有时候她们都不会妥协,那么就会产生死锁。
例子:
class MyLock {
static Object lockA = new Object();
static Object lockB = new Object();
}
public class DeadLock implements Runnable {
public boolean flag = true;
public DeadLock(boolean f) {
this.flag = f;
}
public void run() {
if (flag) {
// while (true) {
synchronized (MyLock.lockA) {
System.out.println("ifLockA");
synchronized (MyLock.lockB) {
System.out.println("ifLockB");
}
// }
}
} else {
// while (true) {
synchronized (MyLock.lockB) {
System.out.println("elseLockB");
synchronized (MyLock.lockA) {
System.out.println("elseLockA");
}
// }
}
}
}
}
public class Text {
public static void main(String[] agrs) {
DeadLock l1 = new DeadLock(true);// 第一个线程
DeadLock l2 = new DeadLock(false);// 第二个线程
new Thread(l1).start();// 开启线程
new Thread(l2).start();// 开启线程
}
}
结果:可能会死锁
例如:
if LockA
else LockB
2、线程间通讯
线程间通信:就是不同的线程共享同一资源,然后对资源进行不同的操作行为,说白了,在执行的线程运行代码是不一样的,但是代码中还含有共享资源。
例子:
/*共享的资源*/
public class Res {
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public StringgetSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
/*输入类*/
public class Input implements Runnable {
private Res r = null;// 定义了一个资源
public Input(Res r) {// 通过构造方法初始化
this.r = r;
}
public void run() {
int x = 0;
while (true) {
if (x == 0) {
this.r.setName("张三");
this.r.setSex("男");
} else {
this.r.setName("Joney");
this.r.setSex("female");
}
x = (x + 1) % 2;
}
}
}
/*输出类*/
public class Output implements Runnable {
private Res re = null;
public Output(Res r) {//初始化资源
this.re = r;
}
public void run() {
while (true) {
System.out.println(this.re.getName() + ":" + this.re.getSex());
}
}
}
/*测试类*/
public class Text {
public static void main(String[] agrs) {
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
new Thread(in).start();
new Thread(out).start();
}
}
从结果中可以看出,结果和我们预测的结果不一样,会出现这样的结果:
Joney:男
张三:female
Joney:female
张三:男
张三:female
3、优化通讯
优化,刚才的通信,就是加上同步锁,在加锁之前,一定要明确,必须是两个或者是多个线程,锁的对象必须是同一个锁
/*输入类*/
public class Input implements Runnable {
private Res r = null;// 定义了一个资源
public Input(Res r) {// 通过构造方法初始化
this.r = r;
}
public void run() {
int x = 0;
while (true) {
synchronized (r) {//加锁,对象指定的是共享资源
if (x == 0) {
this.r.setName("张三");
this.r.setSex("男");
} else {
this.r.setName("Joney");
this.r.setSex("female");
}
}
x = (x + 1) % 2;
}
}
}
/*输出类*/
public class Output implements Runnable {
private Res re = null;
public Output(Res r) {//初始化资源
this.re = r;
}
public void run() {
while (true) {
synchronized (re) {//加锁,对象指定的是共享资源
System.out.println(this.re.getName() + ":" + this.re.getSex());
}
}
}
}
4、等待唤醒机制
利用wait(),notify()和notifyAll()三个方法。
wait()方法是线程放弃的执行资格,notify()唤醒监视器上等待的线程,默认的是从第一个开始。notifyAll()唤醒的是监视器(锁)上所有等待的线程。为什么这三个函数都是在Object类中,因为监视器(锁)对象是任何对象,要用对象来是线程等待和唤醒,那么就得放在Object类中,才能调用任何对象的方法。
在共享资源资源上,定义了一个可以标识资源状态 的标识位,在监视器判断标志位,若不符合执行条件则是线程等待,用此时监视器对象来使线程等待,否则继续执行,到最后改变标志位,然后唤醒的等待的线程(是另外一个共享资源的线程),同样另外一个线程(或者是多个)会执行同样的操作。
只有同一个锁上的被等待的线程,可以被同一个锁上的notify()唤醒,不能对不同锁上的线程进行唤醒,就是等待和唤醒必须是同一个锁。
/*共享的资源*/
public class Res {
private String name;
private String sex;
private boolean flag = false;//标志位,用来表示资源的状态
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
/*输入类*/
public class Input implements Runnable {
private Res r = null;// 定义了一个资源
public Input(Res r) {// 通过构造方法初始化
this.r = r;
}
public void run() {
int x = 0;
while (true) {
synchronized (r) {// 加锁,对象指定的是共享资源
if (r.isFlag())// flag=true表示此时里面有资源,或者是资源没有被读取呢,不能继续添加
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (x == 0) {
this.r.setName("张三");
this.r.setSex("男");
} else {
this.r.setName("Joney");
this.r.setSex("female");
}
x = (x + 1) % 2;
r.setFlag(true);// 标识此时已经赋值了,不能在连续赋值了
r.notify();
}
}
}
}
/*输出类*/
public class Output implements Runnable {
private Res r = null;
public Output(Res r) {// 初始化资源
this.r = r;
}
public void run() {
while (true) {
synchronized (r) {
if (!r.isFlag())// flag=false,标识此时没有资源,或者资源已经被读取了
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.r.getName() + ":" + this.r.getSex());
r.setFlag(false);// 读取资源后,然后把标志为false,标识此时已经被读取出来了,不能在读取了
r.notify();
}
}
}
}
/*测试类*/
public class Text {
public static void main(String[] agrs) {
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
new Thread(in).start();
new Thread(out).start();
}
}
结果:
张三:男
Joney:female
张三:男
Joney:female
张三:男
Joney:female
张三:男
Joney:female
张三:男
5、代码优化
/*共享的资源*/
public class Res {
private String name;
private String sex;
private boolean flag = false;// 标志位,用来表示资源的状态
/*同步函数赋值对象是 this*/
public synchronized void set(String name, String sex) {// 使用同步函数
if (flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name = name;//赋值
this.sex = sex;
this.flag = true;//改变标识位
this.notify();//唤醒等待线程
}
/*同步函数读取 对象是this*/
public synchronized void show() {// 同步函数
if (!flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.name + ":" + this.sex);//读取
this.flag = false;//改变标识位
this.notify();//唤醒等待线程
}
}
/*输入类*/
public class Input implements Runnable {
private Res r = null;// 定义了一个资源
public Input(Res r) {// 通过构造方法初始化
this.r = r;
}
public void run() {
int x = 0;
while (true) {
if (x == 0) {
r.set("张三", "男");
} else {
r.set("Joney", "female");
}
x = (x + 1) % 2;
}
}
}
/*输出类*/
public class Output implements Runnable {
private Res r = null;
public Output(Res r) {// 初始化资源
this.r = r;
}
public void run() {
while (true) {
r.show();
}
}
}
/*测试类*/
public class Text {
public static void main(String[] agrs) {
Res r = new Res();
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}