Java多线程04_线程同步问题

Java多线程04_线程同步问题

关键字 synchronized 可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块


案例1:不安全的买票 (多个线程访问同一个对象的同一个方法):

public class ByTicket {
    
    
	public static void main(String[] args) {
    
    
		BuyThread buyThread = new BuyThread();
		new Thread(buyThread,"zhangsan").start();
		new Thread(buyThread,"lisi").start();
		new Thread(buyThread,"wangwu").start();
	}
}
class BuyThread implements Runnable{
    
    
	
	private int ticketNums = 10;
	boolean flag = true;

	@Override
	public void run() {
    
    
		while(flag) {
    
    
			try {
    
    
				buy();
			} catch (InterruptedException e) {
    
    
				e.printStackTrace();
			}
		}
	}
	
	private void buy() throws InterruptedException {
    
    
		if(ticketNums<=0) {
    
    
			flag = false;
			return;
		}
		
		Thread.sleep(200);
		
		System.out.println(Thread.currentThread().getName()+"买到了"+ ticketNums--);
	}
	
}
wangwu买到了10
zhangsan买到了8
lisi买到了9
lisi买到了7
wangwu买到了7
zhangsan买到了7
zhangsan买到了6
lisi买到了4
wangwu买到了5
lisi买到了3
wangwu买到了3
zhangsan买到了2
wangwu买到了1
lisi买到了0
zhangsan买到了-1

解决办法:在 buy() 方法上增加 synchronized 修饰,使其成为同步方法

private synchronized void buy() throws InterruptedException {
    
    
	
}
zhangsan买到了10
zhangsan买到了9
zhangsan买到了8
wangwu买到了7
wangwu买到了6
wangwu买到了5
lisi买到了4
lisi买到了3
lisi买到了2
lisi买到了1

案例2:不安全的取钱(多个线程操作同一个对象account):

public class Bank {
    
    
	public static void main(String[] args) {
    
    
		Account account = new Account(100,"存款");
		DrawMoney blu = new DrawMoney(account,20,"BLU");
		DrawMoney gf = new DrawMoney(account,100,"gf");
		
		blu.start();
		gf.start();
	}
}

class Account{
    
    
	int money;
	String name;
	
	public Account(int money, String name) {
    
    
		super();
		this.money = money;
		this.name = name;
	}
	
}

class DrawMoney extends Thread{
    
    
	Account account;
	int draw;
	int nowmoney;
	
	public DrawMoney(Account account, int draw, String name) {
    
    
		super(name);
		this.account = account;
		this.draw = draw;
		this.nowmoney = nowmoney;
	}
	
	@Override
	public void run() {
    
    
		
		try {
    
    
			Thread.sleep(1000);
		} catch (InterruptedException e) {
    
    
			e.printStackTrace();
		}
		
		if(account.money-draw<0) {
    
    
			System.out.println(Thread.currentThread().getName()+"账户余额不足");
			return;
		}
		
		account.money = account.money - draw;
		nowmoney = nowmoney + draw;
		System.out.println(account.name+"余额为:"+account.money);
		System.out.println(Thread.currentThread().getName()+"手里的钱:"+nowmoney);
	}
	
}
存款余额为:80
gf手里的钱:100
存款余额为:80
BLU手里的钱:20

解决办法:使用synchronized (account) {} 对给定对象account加锁,进入同步代码块前要获得给定对象的锁

@Override
public void run() {
    
    
	
	synchronized (account) {
    
    
		try {
    
    
			Thread.sleep(1000);
		} catch (InterruptedException e) {
    
    
			e.printStackTrace();
		}
		
		if(account.money-draw<0) {
    
    
			System.out.println(Thread.currentThread().getName()+"账户余额不足");
			return;
		}
		
		account.money = account.money - draw;
		nowmoney = nowmoney + draw;
		System.out.println(account.name+"余额为:"+account.money);
		System.out.println(Thread.currentThread().getName()+"手里的钱:"+nowmoney);
	}

}
存款余额为:80
BLU手里的钱:20
gf账户余额不足

案例3:不安全的集合(原因是两个线程可能会在同一瞬间操作了同一位置):

public class UnsafeList {
    
    
	
	public static void main(String[] args) {
    
    
		List<String> list = new ArrayList<String>();
		for(int i=0;i<10000;i++) {
    
    
			new Thread(()->{
    
    
				list.add(Thread.currentThread().getName());
			}).start();
		}
		System.out.println(list.size());
	}
}
9998

解决办法:锁住 list 对象

import java.util.ArrayList;
import java.util.List;

public class UnsafeList {
    
    
	
	public static void main(String[] args) {
    
    
		List<String> list = new ArrayList<String>();
		for(int i=0;i<10000;i++) {
    
    
			new Thread(()->{
    
    
				synchronized (list) {
    
    
					list.add(Thread.currentThread().getName());
				}
			}).start();
		}
		System.out.println(list.size());
	}
}
10000

猜你喜欢

转载自blog.csdn.net/BLU_111/article/details/108306913