线程的同步与死锁
1:同步问题的引出
class MyThread implements Runnable {
private int ticket = 10 ; // 总票数为10张
@Override
public void run() {
while (true) {
if (this.ticket > 0) {
System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket --);
} else {
System.out.println("***** 票已经卖光了 *****");
break ;
}
}
}
}
public class Test {
public static void main(String[] args) throws Exception {
MyThread mt = new MyThread() ;
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
}
}
//运行结果
票贩子B卖票,ticket = 10
票贩子B卖票,ticket = 8
票贩子A卖票,ticket = 9
票贩子A卖票,ticket = 6
票贩子C卖票,ticket = 9
票贩子C卖票,ticket = 4
票贩子A卖票,ticket = 5
票贩子B卖票,ticket = 7
票贩子B卖票,ticket = 1
***** 票已经卖光了 *****
票贩子A卖票,ticket = 2
***** 票已经卖光了 *****
票贩子C卖票,ticket = 3
***** 票已经卖光了 *****
class MyThread implements Runnable {
private int ticket = 10 ; // 总票数为10张
@Override
public void run() {
while (true) {
if (this.ticket > 0) {
try {
Thread.sleep(100); // 模拟网络延迟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket --);
} else {
System.out.println("***** 票已经卖光了 *****");
break ;
}
}
}
}
public class Test {
public static void main(String[] args) throws Exception {
MyThread mt = new MyThread() ;
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
}
}
票贩子C卖票,ticket = 10
票贩子B卖票,ticket = 8
票贩子A卖票,ticket = 9
票贩子C卖票,ticket = 7
票贩子A卖票,ticket = 6
票贩子B卖票,ticket = 5
票贩子C卖票,ticket = 4
票贩子A卖票,ticket = 2
票贩子B卖票,ticket = 3
票贩子C卖票,ticket = 1
***** 票已经卖光了 *****
票贩子B卖票,ticket = 0
***** 票已经卖光了 *****
票贩子A卖票,ticket = -1
***** 票已经卖光了 *****
三个线程都过了检测那一关
当多个线程访问同一资源的时候,我们如何能够保证数据的完整性,这个时候就需要用同步来解决了
2:线程同步-利用同步代码块进行处理
如果要想在程序之中实现这把锁的功能,就可以使用synchronized关键字来实现,利用此关键字可以定义同步方法或同步代码块,在同步代码块的操作里面的代码只允许一个线程执行。
观察下面的代码来解决上述问题中存在的问题;
class MyThread implements Runnable {
private int ticket = 10 ; // 总票数为10张
@Override
public void run() {
while (true) {
synchronized(this) { // 每一次只允许一个线程进行访问
if (this.ticket > 0) {
try {
Thread.sleep(100); // 模拟网络延迟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket --);
} else {
System.out.println("***** 票已经卖光了 *****");
break ;
}
}
}
}
}
public class Test {
public static void main(String[] args) throws Exception {
MyThread mt = new MyThread() ;
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
}
}
//执行结果
票贩子A卖票,ticket = 10
票贩子C卖票,ticket = 9
票贩子C卖票,ticket = 8
票贩子B卖票,ticket = 7
票贩子B卖票,ticket = 6
票贩子B卖票,ticket = 5
票贩子B卖票,ticket = 4
票贩子B卖票,ticket = 3
票贩子B卖票,ticket = 2
票贩子B卖票,ticket = 1
***** 票已经卖光了 *****
***** 票已经卖光了 *****
***** 票已经卖光了 *****
上述代码加入了同步:加入同步处理之后,程序的整体性能下降了。同步实际上会造成性能的下降。
3;同步问题:利用同步方法解决:只需要在定义的方法上使用synchronized关键字即可
class MyThread implements Runnable {
private int ticket = 10 ; // 总票数为10张
public synchronized boolean sale() {
if (this.ticket > 0) {
try {
Thread.sleep(100); // 模拟网络延迟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket --);
return true ;
} else {
System.out.println("***** 票已经卖光了 *****");
return false ;
}
}
@Override
public void run() {
while (this.sale()) {
;
}
}
}
public class ThreadDemo {
public static void main(String[] args) throws Exception {
MyThread mt = new MyThread() ;
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
}
}
//运行结果
票贩子B卖票,ticket = 10
票贩子B卖票,ticket = 9
票贩子C卖票,ticket = 8
票贩子C卖票,ticket = 7
票贩子C卖票,ticket = 6
票贩子C卖票,ticket = 5
票贩子C卖票,ticket = 4
票贩子C卖票,ticket = 3
票贩子C卖票,ticket = 2
票贩子C卖票,ticket = 1
***** 票已经卖光了 *****
***** 票已经卖光了 *****
***** 票已经卖光了 *****
4:死锁
public class Test implements Runnable {
private Jian jj = new Jian() ;
private XiaoQiang xq = new XiaoQiang() ;
@Override
public void run() {
jj.say(xq);
}
public Test() {
new Thread(this).start();
xq.say(jj);
}
public static void main(String[] args) {
new Test() ;
}
}
class Jian {
public synchronized void say(XiaoQiang xq) {
System.out.println("阿健说:此路是我开,要想从此过,留下10块钱。");
xq.get();
}
public synchronized void get() {
System.out.println("阿健说:得到了10块钱,可以买饭吃了,于是让出了路。");
}
}
class XiaoQiang {
public synchronized void say(Jian jj) {
System.out.println("小强说:让我先跑,我再给你钱。");
jj.get();
}
public synchronized void get() {
System.out.println("小强说:逃过了一劫,可以继续送快餐了。");
}
}
执行效果如下;