Java线程安全问题
1 线程不安全演示
public class Demo {
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);
}
}
}
}
显示结果:出现线程不安全问题
正在准备卖票
正在准备卖票
正在准备卖票
出票成功,余票:9
正在准备卖票
出票成功,余票:7
正在准备卖票
出票成功,余票:8
正在准备卖票
出票成功,余票:6
正在准备卖票
出票成功,余票:5
正在准备卖票
出票成功,余票:4
正在准备卖票
出票成功,余票:3
正在准备卖票
出票成功,余票:2
正在准备卖票
出票成功,余票:2
正在准备卖票
出票成功,余票:1
正在准备卖票
出票成功,余票:0
出票成功,余票:-1
出票成功,余票:-2
2 同步代码块
格式:
synchronize(锁对象){
// 线程执行的操作
}
示例:
public class Demo {
public static void main(String[] args) {
Runnable run = new Ticket();
new Thread(run, "窗口1").start();
new Thread(run, "窗口2").start();
new Thread(run, "窗口3").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(Thread.currentThread().getName() + "正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count);
}else {
break;
}
}
}
}
}
}
显示结果:
窗口1正在准备卖票
窗口1出票成功,余票:9
窗口1正在准备卖票
窗口1出票成功,余票:8
窗口1正在准备卖票
窗口1出票成功,余票:7
窗口1正在准备卖票
窗口1出票成功,余票:6
窗口1正在准备卖票
窗口1出票成功,余票:5
窗口3正在准备卖票
窗口3出票成功,余票:4
窗口3正在准备卖票
窗口3出票成功,余票:3
窗口3正在准备卖票
窗口3出票成功,余票:2
窗口3正在准备卖票
窗口3出票成功,余票:1
窗口3正在准备卖票
窗口3出票成功,余票:0
注意:
- Java中任何对象都可以当做锁对象
- 对于不同的线程需要使用同一个锁对象
3 同步方法
格式:
权限修饰符 synchronize 返回值类型 方法名(){
}
示例:
public class Demo7 {
public static void main(String[] args) {
Runnable run = new Ticket();
new Thread(run, "窗口1").start();
new Thread(run, "窗口2").start();
new Thread(run, "窗口3").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(Thread.currentThread().getName() + "正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count);
return true;
}
return false;
}
}
}
显示结果:
窗口1正在准备卖票
窗口1出票成功,余票:9
窗口1正在准备卖票
窗口1出票成功,余票:8
窗口1正在准备卖票
窗口1出票成功,余票:7
窗口1正在准备卖票
窗口1出票成功,余票:6
窗口1正在准备卖票
窗口1出票成功,余票:5
窗口1正在准备卖票
窗口1出票成功,余票:4
窗口1正在准备卖票
窗口1出票成功,余票:3
窗口1正在准备卖票
窗口1出票成功,余票:2
窗口1正在准备卖票
窗口1出票成功,余票:1
窗口1正在准备卖票
窗口1出票成功,余票:0
注意:
同步方法中的锁对象是this,即当前对象。如果是静态方法则是类名.class。
4 显示锁
格式:
Lock l = new ReentrantLock();
l.lock();
//线程执行任务
l.unlock();
示例:
public class Demo {
public static void main(String[] args) {
Runnable run = new Ticket();
new Thread(run, "窗口1").start();
new Thread(run, "窗口2").start();
new Thread(run, "窗口3").start();
}
static class Ticket implements Runnable{
//票数
private int count = 10;
private Lock l = new ReentrantLock();
@Override
public void run() {
while (true){
l.lock();
if (count > 0) {
//卖票
System.out.println(Thread.currentThread().getName() + "正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count);
}else {
break;
}
l.unlock();
}
}
}
}
显示结果:
窗口1正在准备卖票
窗口1出票成功,余票:9
窗口1正在准备卖票
窗口1出票成功,余票:8
窗口1正在准备卖票
窗口1出票成功,余票:7
窗口1正在准备卖票
窗口1出票成功,余票:6
窗口1正在准备卖票
窗口1出票成功,余票:5
窗口1正在准备卖票
窗口1出票成功,余票:4
窗口1正在准备卖票
窗口1出票成功,余票:3
窗口1正在准备卖票
窗口1出票成功,余票:2
窗口1正在准备卖票
窗口1出票成功,余票:1
窗口1正在准备卖票
窗口1出票成功,余票:0
5 公平锁与不公平锁
公平锁:先来先得,排队抢占锁
不公平锁:随机抢占锁
创建锁对象是默认是不公平锁,在创建显示锁对象时,构造方法中传入true可将锁对象设置为公平锁。