1、购票(不安全策略)
代码片段:
public class Main {
private static int ticket = 10;
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
while(ticket > 0) {
try {
ticket--;
Thread.sleep(1000);
System.out.println("卖出了一张票,还剩下"+ticket+"张票");
}catch (Exception e) {
e.printStackTrace();
}
}
}
};
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
}
}
显示结果:
卖出了一张票,还剩下6张票
卖出了一张票,还剩下5张票
卖出了一张票,还剩下5张票
卖出了一张票,还剩下5张票
卖出了一张票,还剩下2张票
卖出了一张票,还剩下2张票
卖出了一张票,还剩下2张票
卖出了一张票,还剩下2张票
卖出了一张票,还剩下0张票
卖出了一张票,还剩下0张票
2、购票(安全策略)
- 给方法加入synchronized解决线程不安全问题
代码片段:
public class Main {
private static int ticket = 10;
public static void main(String[] args) {
Runnable r = new Runnable() {
public synchronized void run() {
while(ticket > 0) {
try {
ticket--;
Thread.sleep(1000);
System.out.println("卖出了一张票,还剩下"+ticket+"张票");
}catch (Exception e) {
e.printStackTrace();
}
}
}
};
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
}
}
显示结果:
卖出了一张票,还剩下9张票
卖出了一张票,还剩下8张票
卖出了一张票,还剩下7张票
卖出了一张票,还剩下6张票
卖出了一张票,还剩下5张票
卖出了一张票,还剩下4张票
卖出了一张票,还剩下3张票
卖出了一张票,还剩下2张票
卖出了一张票,还剩下1张票
卖出了一张票,还剩下0张票
注:第一个线程进入run()后,其他进程无法进入,直到第一个线程执行完毕才允许其他进程进入,而此时ticket已经为0,其他进程不能进入循环体,因此,退出。
其中,形如synchronized (Main.class) {}包含代码块的结构也能达到同样的效果。
3、wait()和notify()
代码片段:
public class Main {
public static void main(String[] args) {
new Thread() {
public void run() {
synchronized (Main.class) {
System.out.println("T1 start!");
try {
Main.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T1 end!");
}
}
}.start();
new Thread() {
public void run() {
synchronized (Main.class) {
System.out.println("T2 start!");
Main.class.notify(); //唤醒
System.out.println("T2 end!");
}
}
}.start();
}
}
结果显示:
T1 start!
T2 start!
T2 end!
T1 end!
解析:wait()和notify()一系列的方法,是属于对象的,不是属于线程的。它们用在线程同步时,synchronized语句块中。
wait()方法可以使线程进入等待状态,而notify()可以使等待的状态唤醒。这样的同步机制十分适合生产者、消费者模式:消费者消费某个资源,而生产者生产该资源。当该资源缺失时,消费者调用wait()方法进行自我阻塞,等待生产者的生产;生产者生产完毕后调用notify/notifyAll()唤醒消费者进行消费。
4、wait()
和notify()
精细控制
代码片段:
public class Main {
public static void main(String[] args) {
final Object object = new Object();
new Thread() {
public void run() {
synchronized (object) {
System.out.println("T1 start!");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T1 end!");
}
}
}.start();
new Thread() {
public void run() {
synchronized (object) {
System.out.println("T2 start!");
object.notify();
System.out.println("T2 end!");
}
}
}.start();;
new Thread() {
public void run() {
synchronized (object) {
System.out.println("T3 start!");
object.notify();
System.out.println("T3 end!");
}
}
}.start();;
new Thread() {
public void run() {
synchronized (object) {
System.out.println("T4 start!");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T4 end!");
}
}
}.start();
}
}
结果显示:
T1 start!
T2 start!
T2 end!
T1 end!
T3 start!
T3 end!
T4 start!
很容易看出来,T4,它启动了,但是wait了,后面已经没有线程了,它的wait永远不会有线程帮它notify了!于是,T4 (T4 end!没法执行到)它就这么等着!