解决多线程安全方式:
sychronized: jvm维护,隐式锁
1. 同步代码块
2. 同步方法
用例:
package com.denganzhi.pp;
class Web12306Demo implements Runnable{
private int num=50;
boolean isRunning=true;
@Override
public void run() {
while(isRunning){
getCard4();
}
}
// 线程不安全
// 3 个线程 可能 同时进入方法
public void getCard0() {
if(num<1) {
isRunning=false;
return;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/***
* 出现问题:
* C 抢到了,第0张票
A 抢到了,第-1张票
*/
System.out.println(Thread.currentThread().getName()+" 抢到了,第"+ (num--)+ "张票");
}
// 线程安全,只有一个线程可以进入方法
public synchronized void getCard1() {
if(num<1) {
isRunning=false;
return;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 抢到了,第"+ (num--)+ "张票");
}
// 线程安全
public void getCard2() {
// this 同一时刻只能被一个 线程 持有
synchronized (this) {
if(num<1) {
isRunning=false;
return;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 抢到了,第"+ (num--)+ "张票");
}
}
// 线程不安全,锁定范围不正确
public void getCard3() {
synchronized (this) {
if(num<1) {
isRunning=false;
return;
}
}
// a,b,c 线程可能同时出现在这里
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 抢到了,第"+ (num--)+ "张票");
}
// 线程不安全
// 锁定资源不正确 ,基础类型 无法锁定
public void getCard4() {
synchronized ((Integer)num) {
if(num<1) {
isRunning=false;
return;
}
}
// B 抢到了,第0张票
// C 抢到了,第-1张票
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 抢到了,第"+ (num--)+ "张票");
}
}
public class Main2 {
public static void main(String[] args) {
Web12306Demo web1236=new Web12306Demo();
new Thread(web1236,"A").start();
new Thread(web1236,"B").start();
new Thread(web1236,"C").start();
}
}
3. A,B线程同时锁住资源,互相不释放
package com.denganzhi.pp;
public class Main3 {
public static void main(String[] args) {
Object goods=new Object();
Object money=new Object();
// 2 个线程 访问同一份 资源
/**
* 死锁 ,2个线程都锁住,同一份资源,互相不释放,
* 表现:程序阻塞,无法输出system.out.pintln
*/
Test1 test1=new Test1(goods,money);
Test2 test2=new Test2(goods,money);
Thread thread1=new Thread(test1);
thread1.start();
Thread thread2=new Thread(test2);
thread2.start();
}
}
class Test1 implements Runnable{
// 资源,线程中的资源,不是 线程共享资源
// Object goods=new Object();
// Object money=new Object();
Object goods;
Object money;
public Test1(Object goods, Object money) {
super();
this.goods = goods;
this.money = money;
}
@Override
public void run() {
while(true) {
test();
}
}
public void test() {
synchronized(goods) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (money) {
}
}
System.out.println("一手货,一手给钱");
}
}
class Test2 implements Runnable{
// 资源,线程中的资源,不是 线程共享资源
// Object goods=new Object();
// Object money=new Object();
Object goods=null;
Object money=null;
public Test2(Object goods, Object money) {
super();
this.goods = goods;
this.money = money;
}
@Override
public void run() {
while(true) {
test();
}
}
public void test() {
synchronized(money) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (goods) {
}
}
System.out.println("一手给钱,一手给货");
}
}
3. 同步锁Lock jdk1.5以后, 上锁以后必须unlock[在finally]
案例:买票代码
1.1. 问题代码:
package com.denganzhi.pp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main2 {
public static void main(String[] args) {
AtomicDemo auAtomicDemo=new AtomicDemo();
Thread thread=null;
for (int i = 0; i < 10; i++) {
thread=new Thread(auAtomicDemo);
thread.setName("线程:"+i );
thread.start();
}
}
}
class AtomicDemo implements Runnable{
// 还 剩下 10 张票 ,10个人来 抢票
private int num=10;
Lock lock=new ReentrantLock();
@Override
public void run() {
// TODO Auto-generated method stub
//lock.lock(); // 上锁
try {
Thread.sleep(50);
int num=getSerialNumber();
if(num <= 0){
System.err.println(Thread.currentThread().getName() +" 没有抢到火车票");
}else{
System.out.println(Thread.currentThread().getName() +" 抢到第" + num + "张火车票");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//lock.unlock(); //释放锁
}
}
public int getSerialNumber() {
return num--;
}
}
运行结果: 一张火车票被多个人抢到,数据错误
线程:7 抢到第10张火车票
线程:8 抢到第7张火车票
线程:4 抢到第9张火车票
线程:3 抢到第9张火车票
线程:5 抢到第10张火车票
线程:0 抢到第8张火车票
线程:2 抢到第8张火车票
线程:1 抢到第8张火车票
线程:9 抢到第10张火车票
线程:6 抢到第10张火车票
3. 同步锁Lock jdk1.5以后, 上锁以后必须unlock[在finally]
package com.denganzhi.pp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main2 {
public static void main(String[] args) {
AtomicDemo auAtomicDemo=new AtomicDemo();
Thread thread=null;
for (int i = 0; i < 10; i++) {
thread=new Thread(auAtomicDemo);
thread.setName("线程:"+i );
thread.start();
}
}
}
class AtomicDemo implements Runnable{
// 还 剩下 10 张票 ,10个人来 抢票
private int num=10;
Lock lock=new ReentrantLock();
@Override
public void run() {
// TODO Auto-generated method stub
lock.lock(); // 上锁
try {
Thread.sleep(50);
int num=getSerialNumber();
if(num <= 0){
System.err.println(Thread.currentThread().getName() +" 没有抢到火车票");
}else{
System.out.println(Thread.currentThread().getName() +" 抢到第" + num + "张火车票");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
lock.unlock(); //释放锁
}
}
public int getSerialNumber() {
return num--;
}
}
正确输出结果:
线程:0 抢到第10张火车票
线程:1 抢到第9张火车票
线程:2 抢到第8张火车票
线程:3 抢到第7张火车票
线程:4 抢到第6张火车票
线程:5 抢到第5张火车票
线程:6 抢到第4张火车票
线程:7 抢到第3张火车票
线程:8 抢到第2张火车票
线程:9 抢到第1张火车票
本文深入探讨了多线程环境下实现线程安全的各种方法,包括synchronized关键字、显式锁Lock的使用及其实现原理,通过具体示例展示了如何避免线程间的竞争条件和死锁,确保数据的一致性和程序的正确运行。
4976

被折叠的 条评论
为什么被折叠?



