「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」
线程的安全问题:
案例:卖票
public class Ticket implements Runnable{
// 票的数量
private int ticket = 100;
@Override
public void run() {
while (true){
if (ticket == 0){
break;
}else {
ticket--;
System.out.println(Thread.currentThread().getName() + "在卖票" + ticket + "张票");
}
}
}
}
public class Demo {
public static void main(String[] args) {
Ticket ticket1 = new Ticket();
Thread t1 = new Thread(ticket1);
Thread t2 = new Thread(ticket1);
Thread t3 = new Thread(ticket1);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
public class Ticket implements Runnable{
// 票的数量
private int ticket = 100;
@Override
public void run() {
while (true){
if (ticket == 0){
break;
}else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
System.out.println(Thread.currentThread().getName() + "在卖票" + ticket + "张票");
}
}
}
}
卖票案例数据安全问题的解决:
为什么出现问题?(这也是我们判断多线程程序是否会有数据安全问题的标准)
多线程操作共享数据
如何解决多线程安全问题呢?
基本思想:让程序没有安全问题的环境。
怎么实现呢?
把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。
Java提供了同步代码块的方式来解决。
同步代码块:
public class Ticket implements Runnable{
// 票的数量
private int ticket = 100;
private Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){ // 多个线程必须使用同一把锁
if (ticket <= 0){
break;
}else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
System.out.println(Thread.currentThread().getName() + "在卖票" + ticket + "张票");
}
}
}
}
}
以下代码 或出现负数票。锁有问题
public class MyThread extends Thread{
private static int tiketCount = 100;
@Override
public void run() {
while (true){
synchronized (this){
if (tiketCount <= 0){
break;
}else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
tiketCount --;
System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + tiketCount + "张票");
}
}
}
}
}
public class Demo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("窗口1");
t2.setName("窗口2");
t1.start();
t2.start();
}
}
一定要保证 锁对象是唯一的。
public class MyThread extends Thread{
private static int tiketCount = 100;
private static Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if (tiketCount <= 0){
break;
}else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
tiketCount --;
System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + tiketCount + "张票");
}
}
}
}
}
同步方法:
public class MyThreadRunable implements Runnable {
private static int ticketCount = 100;
@Override
public void run() {
while (true){
if ("窗口1".equals(Thread.currentThread().getName())){
// 同步方法
boolean result = synchronizedMethod();
if (result){
break;
}
}
if ("窗口2".equals(Thread.currentThread().getName())){
// 同步代码块
synchronized (this){
if (ticketCount == 0){
break;
}else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticketCount--;
System.out.println(Thread.currentThread().getName() + "在卖票" + ticketCount + "张票");
}
}
}
}
}
private synchronized boolean synchronizedMethod(){
if (ticketCount == 0){
return true;
}else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticketCount--;
System.out.println(Thread.currentThread().getName() + "在卖票" + ticketCount + "张票");
return false;
}
}
}
public class Demo {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
t1.setName("窗口1");
t2.setName("窗口2");
t1.start();
t2.start();
}
}
Lock 锁
public class Ticket implements Runnable {
// 票的数量
private int ticket = 100;
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();
if (ticket <= 0) {
break;
} else {
Thread.sleep(100);
ticket--;
System.out.println(Thread.currentThread().getName() + "在卖票" + ticket + "张票");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
死锁:
public class Demo {
public static void main(String[] args) {
Object objA = new Object();
Object objB = new Object();
new Thread(()->{
while (true){
synchronized (objA){
synchronized (objB){
System.out.println("小康同学在走路");
}
}
}
}).start();
new Thread(()->{
while (true){
synchronized (objB){
synchronized (objA){
System.out.println("小微同学在走路");
}
}
}
}).start();
}
}