一、线程安全问题
package pers.h.express.main;
/**
* @author s
* @version 1.0
* @date 2022-02-09 13:14
*/
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);
}
}
}
}
查看以上代码,发现当三个线程同时执行时,操作同一个变量count,就会出现余票为负数的情况。
解决线程不安全问题的方法:
(一)同步代码块
package pers.h.express.main;
/**
* @author s
* @version 1.0
* @date 2022-02-09 13:14
*/
public class Demo2 {
/**
* 线程同步:synchronized
* @param args
* */
public static void main(String[] args){
// 线程不安全
// 解决方案1:同步代码块
// 格式:synchronized(锁对象){}
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;
}
}
}
}
}
}
(二)同步方法
package pers.h.express.main;
/**
* @author s
* @version 1.0
* @date 2022-02-09 13:14
*/
public class Demo3 {
/**
* 线程同步:synchronized
* @param args
* */
public static void main(String[] args){
// 线程不安全
// 解决方案2:同步方法
// 格式:synchronized(锁对象){}
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){
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;
}
return false;
}
}
}
以上两种方法都属于隐式锁。
(三)、线程同步-Lock 显示锁
package pers.h.express.main;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author s
* @version 1.0
* @date 2022-02-09 13:14
*/
public class Demo4 {
/**
* 线程同步:Lock
* @param args
* */
public static void main(String[] args){
// 线程不安全
// 解决方案3:显示锁 Lock 子类 ReentrantLock
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 lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.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;
}
lock.unlock();
}
}
}
}
显示锁lock与隐式锁synchroined的区别:
1、使用方法不同:
lock需要手动的获取和释放锁。
synchronized代码块执行完成后,系统会自动让程序释放占用的锁。
2、构成不同:
synchronized:是JAVA中的关键字,由JVM来维护,是JVM层面的锁;
lock:是JDK5后出现的具体的类,是API层面的锁。
3、等待是否可中断
lock显示锁可以中断,隐式锁不可以中断,除非抛出异常。
二、公平锁与非公平锁
以上三种方法都是非公平锁。
显示锁 new ReentrantLock(true);传参为true时即为公平锁。
三、线程死锁
package pers.h.express.main;
/**
* @author s
* @version 1.0
* @date 2022-02-10 17:17
*/
public class Demo5 {
public static void main(String[] args) {
// 线程死锁
Culprit c = new Culprit();
Police p = new Police();
new MyThread(c,p).start();
c.say(p);
}
static class MyThread extends Thread{
private Culprit c;
private Police p;
public MyThread(Culprit c,Police p){
this.c = c;
this.p = p;
}
@Override
public void run() {
p.say(c);
}
}
// 罪犯
static class Culprit{
public synchronized void say(Police p){
System.out.println("罪犯:你放了我,我放了人质!");
p.fun();
}
public synchronized void fun(){
System.out.println("罪犯被放走了,罪犯放了人质!");
}
}
// 警察
static class Police{
public synchronized void say(Culprit c){
System.out.println("警察:你放了人质,我放过你!");
c.fun();
}
public synchronized void fun(){
System.out.println("警察救了人质,但罪犯跑了");
}
}
}