假如有十张票,现在需要三个窗口(线程)卖,代码如下:
package com.test.runnable;
class MyThread implements Runnable {
private int ticket = 10;
public void run() {
while (ticket > 0) {
System.out.println("ticket = " + ticket--);
try {
Thread.sleep(2000l);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class RunnableDemo{
public static void main(String[] args){
MyThread my = new MyThread();
new Thread(my).start();
new Thread(my).start();
new Thread(my).start();
}
}
输出结果为:
ticket = 10
ticket = 9
ticket = 8
ticket = 7
ticket = 7
ticket = 7
ticket = 6
ticket = 5
ticket = 6
ticket = 4
ticket = 4
ticket = 3
ticket = 2
ticket = 1
ticket = 2
可以发现不止卖 了十张,所以要进行并发控制。
第一种办法,采用同步关键字
package com.test.runnable;
class MyThread implements Runnable {
private int ticket = 10;
synchronized public void run() {
while (ticket > 0) {
System.out.println("ticket = " + ticket--);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class RunnableDemo{
public static void main(String[] args){
MyThread my = new MyThread();
new Thread(my).start();
new Thread(my).start();
new Thread(my).start();
}
}
可以发现输出结果为:
ticket = 10
ticket = 9
ticket = 8
ticket = 7
ticket = 6
ticket = 5
ticket = 4
ticket = 3
ticket = 2
ticket = 1
这样多个窗口卖票,就能正确了,
2.也可以采用原子变量
package com.test.runnable;
import java.util.concurrent.atomic.AtomicInteger;
class MyThread implements Runnable {
private AtomicInteger ticket = new AtomicInteger(10);
synchronized public void run() {
while (ticket.get() > 0) {
System.out.println("ticket = " + ticket.getAndAdd(-1));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class RunnableDemo{
public static void main(String[] args){
MyThread my = new MyThread();
new Thread(my).start();
new Thread(my).start();
new Thread(my).start();
}
}
3.采用信号量Semaphore
package com.test.runnable;
import java.util.concurrent.Semaphore;
class MyThread implements Runnable {
final Semaphore semp = new Semaphore(1);
private int ticket = 10;
public void run() {
// 获取许可
try {
semp.acquire();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while (ticket > 0) {
System.out.println("ticket = " + ticket--);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 访问完后,释放
semp.release();
}
}
public class RunnableDemo{
public static void main(String[] args){
MyThread my = new MyThread();
new Thread(my).start();
new Thread(my).start();
new Thread(my).start();
}
}
4.采用Lock
package com.test.runnable;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class MyThread implements Runnable {
private Lock myLock = new ReentrantLock(); // 执行操作所需的锁对象
private int ticket = 10;
public void run() {
myLock.lock();
while (ticket > 0) {
System.out.println("ticket = " + ticket--);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 访问完后,释放
myLock.unlock();
}
}
public class RunnableDemo{
public static void main(String[] args){
MyThread my = new MyThread();
new Thread(my).start();
new Thread(my).start();
new Thread(my).start();
}
}
5.但不能采用volatile关键字,因为线程内变量的值更新依赖原值。
package com.test.runnable;
class MyThread implements Runnable {
//private volatile int ticket = 10;
private volatile int ticket = 10;
public void run() {
while (ticket > 0) {
System.out.println("ticket = " + ticket--);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class RunnableDemo{
public static void main(String[] args){
MyThread my = new MyThread();
new Thread(my).start();
new Thread(my).start();
new Thread(my).start();
}
}