同步
多线程数据不同步的三种解决方法
需求:深圳罗湖火车站目前正在出售车票,共有100张票,而它有3个售票窗口售票
解决办法:
1.同步代码块
2.同步方法
3.同步锁
可能出现线程安全的问题的情况:
1.存在多线程环境
2.多个线程共享同一份数据
3.多个线程操作同一份数据并且共享数据做了修改
4.存在多条语句操作共享数据
在多线程环境下,存在多条语句操作共享数据,并且对数据做了修改的操作,那么必定会出现线程安全问题
解决办法: 将多条操作共享数据的语句 包裹起来,同步锁
//多线程数据不同步的三种解决方法
public static void main(String[] args) {
// TODO Auto-generated method stub
//SellThread1 st = new SellThread1();//方法1
//SellThread2 st = new SellThread2();//方法2
SellTh3 st = new SellTh3();//方法3
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
Thread t3 = new Thread(st);
t1.setName("窗口A");
t2.setName("窗口B");
t3.setName("窗口C");
t1.start();
t2.start();
t3.start();
}
方式1:同步代码块:
enum MyLook{LOCK}//定义枚举,lock是静态final类对象
class SellThread1 implements Runnable{
private int tickets=100;//不用加static因为只创建了一个接口子类对象
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
synchronized(MyLook.LOCK){//此处放一个静态final对象
if(tickets>0){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"还剩:"+(--tickets));
}
}
}
}
}
方法2:同步方法
格式:
public synchronized 返回值 方法名(参数列表) {
//需要同步的代码块
}
如果锁对象是this,就可以考虑使用同步方法。
如果方式静态方法, 当前类对应的字节码文件对象作锁
Class c = SellTicketThread.class
静态方法和默认的类字节码文件做对象可以使用Thread的子类来实现功能:
(只有这种情况下我才会用Thread,因为是Thread的字节码文件做锁)
class SellThread2 implements Runnable{
private int tis=100;
//private static int tis=100;//静态
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
sellt();
}
}
//静态public static synchronized void sellt()
public synchronized void sellt(){
if(tis>0){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+(--tis));
}
}
}
方法二的Thread:
/*class SellTicketThread extends Thread {
private static int tickets = 100;
@Override
public void run() {
while (true) {
sellTicket();
}
}
public static synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票");
}
}
}*/
方法3 创建锁对象
Lock lock=new ReentrantLock();//创建锁对象
//方法三:加锁,创建锁对象
class SellTh3 implements Runnable{
private int tis=100;
Lock lock=new ReentrantLock();//创建锁对象
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
lock.lock();
if(tis>0){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+(--tis));
}
lock.unlock();
}
}
}
死锁:
死锁:指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象。
- 代码演示死锁现象。
- 总共有四种情况会死锁
public class DeadThradDemo {
public static void main(String[] args) {
DieLock dl1 = new DieLock(true);
DieLock dl2 = new DieLock(false);
dl1.start();
dl2.start();
}
}
class DieLock extends Thread {
private boolean flag;
public DieLock() {
}
public DieLock(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag) {
// dl1进来
synchronized (TestLock.LOCKA) {
System.out.println("if 语句中 LockA锁");
synchronized (TestLock.LOCKB) {
System.out.println("if 语句中 LockB锁");
}
}
} else {
// dl走else
synchronized (TestLock.LOCKB) {
System.out.println("else 语句中 lockB锁");
synchronized (TestLock.LOCKA) {
System.out.println("else 语句中 lockA锁");
}
}
}
}
}
class TestLock {
public static final Object LOCKA = new Object();
public static final Object LOCKB = new Object();
}