多线程之间由于抢占式运行,存在线程不安全的问题。如:
public class Demo_safe {
public static void main(String[] args) {
//线程不安全
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//票数
private int count = 10;
@Override
public void run() {
while (count>0){
//卖票
System.out.println("准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println("出票成功,余票:"+count);
}
}
}
}
输出:
准备卖票
准备卖票
准备卖票
出票成功,余票:8
准备卖票
出票成功,余票:9
准备卖票
出票成功,余票:7
准备卖票
出票成功,余票:4
准备卖票
出票成功,余票:5
准备卖票
出票成功,余票:6
准备卖票
出票成功,余票:1
准备卖票
出票成功,余票:2
准备卖票
出票成功,余票:3
准备卖票
出票成功,余票:-2
出票成功,余票:-1
出票成功,余票:0
出现了负数,明显不合理,存在不安全问题
实现线程安全有如下方法:
一、同步代码块
格式: synchronized(锁对象){}
注意: 一定要所有线程都看同一把锁才能保证排队,以保证线程安全。
import java.io.ObjectOutputStream;
public class Demo_safe1 {
public static void main(String[] args) {
//线程不安全
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable {
//票数
private int count = 10;
private Object o = new Object();
@Override
public void run() {
while (true) {
synchronized (o) {
if (count > 0) {
//卖票
System.out.println("准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count);
}else {
break;
}
}
}
}
}
}
准备卖票
Thread-0出票成功,余票:9
准备卖票
Thread-0出票成功,余票:8
准备卖票
Thread-0出票成功,余票:7
准备卖票
Thread-0出票成功,余票:6
准备卖票
Thread-0出票成功,余票:5
准备卖票
Thread-0出票成功,余票:4
准备卖票
Thread-2出票成功,余票:3
准备卖票
Thread-2出票成功,余票:2
准备卖票
Thread-2出票成功,余票:1
准备卖票
Thread-2出票成功,余票:0
二、同步方法
public class Demo_safe2 {
public static void main(String[] args) {
//线程不安全
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable {
//票数
private int count = 10;
@Override
public void run() {
while (true) {
boolean flag = sale();
if (!flag){
break;
}
}
}
public synchronized boolean sale(){
if (count > 0) {
//卖票
System.out.println("准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"出票成功,余票:" + count);
return true;
}else {
return false;
}
}
}
}
以上同步代码块 与 同步方法 都属于隐式锁
三、显示锁Lock
其子类 ReentrantLock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo_safe3 {
public static void main(String[] args) {
//线程不安全
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable {
//票数
private int count = 10;
//显示锁
//private Lock l = new ReentrantLock(true); 当传入参数"true",则表示为公平锁
private Lock l = new ReentrantLock();
@Override
public void run() {
while (true) {
l.lock();
if (count > 0) {
//卖票
System.out.println("准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"出票成功,余票:" + count);
}else {
break;
}
l.unlock();
}
}
}
}