线程安全
1. 同步代码块:
通过在类里私有对象,锁住synchronized所包含的区域
格式:synchronized(锁对象){}
package xc;
public class Demo8 {
public static void main(String[] args) {
Runnable t = new Ticket();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
static class Ticket implements Runnable {
//票数
private int count = 10;
private Object o = new Object();
@Override
public void run() {
while (count > 0) {
synchronized (o) {
System.out.println(Thread.currentThread().getName() + "正在买票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println("卖票成功,还有票数:" + count);
}
}
}
}
}
2. 同步方法
以方法为单位,把synchronized修饰到方法里
public synchronized boolean sate() {}
package xc;
public class Demo8 {
public static void main(String[] args) {
Runnable t = new Ticket();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
static class Ticket implements Runnable {
//票数
private int count = 10;
//private Object o = new Object();
@Override
public void run() {
while (true) {
boolean flag = sate();
if(!flag){
break;
}
// synchronized (o) {
// System.out.println(Thread.currentThread().getName() + "正在买票");
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// count--;
// System.out.println("卖票成功,还有票数:" + count);
// }
}
}
//把需要同步的内容定义成一个方法
public synchronized boolean sate() {
if (count > 0) {
System.out.println(Thread.currentThread().getName() + "正在买票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println("卖票成功,还有票数:" + count);
return true;
}else {
return false;
}
}
}
}
3.显示锁
将锁创建出来
Lock s = new ReentrantLock();
s.lock();锁住
s.unlock();解开
package xc;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo9 {
public static void main(String[] args) {
Runnable t = new Ticket();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
static class Ticket implements Runnable {
//票数
private int count = 10;
//锁
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("卖票成功,还有票数:" + count);
l.unlock();
} else {
break;
}
}
}
}
}
前两个是隐式锁,最后一个是隐式锁
一、隐式锁
隐式锁中又分为同步代码块和同步方法,但是都是基于Synchronized关键字来实现的,因为他只需要是使用管关键字就可以,不用显示加锁和解锁的过程,所以称之为隐式锁。
二、显示锁Lock
显式锁的概念是相对于隐式锁的,因为显式锁在使用的时候程序员可以控制上锁和解锁,所以称之为显式锁。
区别:
1、内存泄漏
隐式锁:简单易用且不会导致内存泄漏。
显式锁:完全要程序员控制,容易导致锁泄露。
2、是否可中断
隐式锁:不可中断的。除非抛出异常或者正常运行完成
显式锁:可以中断。
7、精确唤醒
隐式锁:不能精确唤醒一个线程。要么随机唤醒一个线程;要么是唤醒所有等待的线程。
显式锁:能精确唤醒一个线程。实现分组唤醒需要唤醒的线程。
四、共同点
1、无论是显式锁还是隐式锁,当被锁住的代码块执行结束以后,正在等待的线程 开始抢时间偏执行代码块,并不是先来后到的方式进行执行,而是随机的的抢到时间偏就执行。
2、被锁住的代码块,谁先抢到时间偏进行代码执行以后,再次抢到的概率会增加,连续抢到的概率很大。
3、都可以解决线程安全问题