线程安全问题
解决方法1:
线程安全1-同步代码块
格式:
synchronized(锁对象){
}
public class Demo_synchronized {
public static void main(String[] args) {
//Runnable r = new Ticket();
Ticket r = new Ticket();//同一个任务
new Thread(r).start();//多线程完成同一任务
new Thread(r).start();
new Thread(r).start();
}
static class Ticket implements Runnable{
//票数
private int count = 10;
//注意所有线程只能有一把锁
private Object o = new Object();//同一任务o只有一个
@Override
public void run() {
while(true){
//抢到该锁执行下列程序
synchronized (o){
if(count>0){
//卖票
System.out.println("正在准备卖票");
//睡眠1s
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"余票"+count);
}else{
//没有余票则结束线程
return;
}
}
}
}
}
}
若没有锁住,可能会导致一个线程卖了一张票,还没有进行count–,另一线程进行操作,导致最后count可能出现负数
有锁之后,排队操作synchronized(锁对象){}中间的内容
解决方法2
线程安全2-同步方法
public class Demo_synchronized2 {
public static void main(String[] args) {
//一个任务
Runnable r = new Ticket();
//三个线程执行一个任务,锁对象是r
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
}
static class Ticket implements Runnable{
//票数
private int count = 10;
private Object o = new Object();
@Override
public void run() {
//private Object o = new Object();//若在此处创建o,代表每个线程会new一个o,看的不是同一把锁,就没有达到目的
while(true){
Boolean flag = sale();
if(!flag){
break;
}
}
}
//同步方法,synchronized修饰方法,锁对象是this
public synchronized Boolean sale(){
//非静态对象 锁对象是this
//静态对象 锁对象是Ticket.class
//抢到该锁执行下列程序
if(count>0){
//卖票
System.out.println("正在准备卖票");
//睡眠1s
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"余票"+count);
return true;
}else{
//没有余票则结束线程
return false;
}
}
}
}
同步代码块和同步方法都属于隐式锁
解决方法3:
线程安全3-显示锁Lock
fair参数是true,表示是公平锁
static class Ticket implements Runnable{
//票数
private int count = 10;
//ReentrantLock()是Lock接口的实现类
//向上转型
Lock l = new ReentrantLock();
@Override
public void run() {
while(true){
l.lock();
//抢到该锁执行下列程序
if(count>0){
//卖票
System.out.println("正在准备卖票");
//睡眠1s
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"余票"+count);
}else{
//没有余票则结束线程
return;
}
l.unlock();
}
}
}
显示锁和隐式锁的区别:
链接: link.
synchronized是Java的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。JDK1.5以后引入了自旋锁、锁粗化、轻量级锁,偏向锁来有优化关键字的性能。
Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。