假如有十张票,现在需要三个窗口(线程)卖,代码如下:
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();
}
}
或者同步代码块
while(ticket>0){
synchronized (this){
System.out.println(ticket--);
}
try{
Thread.sleep(200l);
}catch (Exception e){
e.printStackTrace();
}
}
ticket = 10
ticket = 9
ticket = 8
ticket = 7
ticket = 6
ticket = 5
ticket = 4
ticket = 3
ticket = 2
ticket = 1
这样多个窗口卖票,就能正确了,
原子变量
package com.test.runnable;
import java.util.concurrent.atomic.AtomicInteger;
class MyThread implements Runnable {
private AtomicInteger ticket = new AtomicInteger(10);
synchronized public void run() { //这里加 synchronized 是为了顺序输出,不加的话,三个线程不是顺序输出
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();
}
}
信号量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();
}
}
ReentrantLock
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();
}
}
不能采用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();
}
}