1、方法声明加上synchronize关键词
注意:若不加上synchronize关键词,则线程会不安全,输出的结果有人会拿到第-1张票
//解决并发问题,在执行增删改的方法加上关键词synchronized
public class TestSyn1 {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket,"小明").start();
new Thread(buyTicket,"小红").start();
new Thread(buyTicket,"黄牛").start();
}
}
class BuyTicket implements Runnable {
private int tickets = 10;
private boolean flag = true;
@Override
public void run() {
while (flag == true){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("程序出错!");
}
}
}
public synchronized void buy() throws InterruptedException {
//判断是否有票
if (tickets <= 0){
flag = false;
return;
}
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() +
"拿到第" + tickets-- + "张票");
}
}
2、使用synchronize同步块
使用synchronize同步块控制不同线程使用的相同对象
注意:需要避免synchronized同步块嵌套使用,会死锁!
//解决并发问题,使用synchronized同步块控制执行增删改的对象
public class Testsyn2 {
public static void main(String[] args) {
//生成一张银行卡
BankAccount account = new BankAccount(1000,"银行卡");
//创建两个线程同时取钱,但由于synchronized同步块控制执行,女朋友取不到钱
new Thread(new BankCard(account,1000),"你").start();
new Thread(new BankCard(account,10),"女朋友").start();
}
}
//银行账户
class BankAccount {
private int money; //卡内余额
private String money_name; //钱的名字
public BankAccount(int money, String money_name) {
this.money = money;
this.money_name = money_name;
}
public String getMoney_name() {
return money_name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
//银行卡
class BankCard implements Runnable {
BankAccount bankAccount; //银行账户
private int balance; //余额
private int withdraw_money; //取多少钱
public BankCard(BankAccount bankAccount, int withdraw_money) {
this.bankAccount = bankAccount;
this.withdraw_money = withdraw_money;
}
@Override
public void run() {
try {
withdraw_money();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取钱方法
private void withdraw_money() throws InterruptedException {
//synchronized同步块
synchronized (bankAccount){
if (bankAccount.getMoney() - withdraw_money < 0){
System.out.println(Thread.currentThread().getName() +
"取钱时发现银行卡余额不足~");
return;
}
//模拟延时
Thread.sleep(100);
//取钱
bankAccount.setMoney(bankAccount.getMoney() - withdraw_money);
//拿到手的钱
balance += withdraw_money;
//输出
System.out.println(Thread.currentThread().getName() +
"手里的钱:" + balance);
System.out.println(bankAccount.getMoney_name() +
"余额为:" +bankAccount.getMoney());
}
}
3、使用Lock锁
和synchronized不同的是,Lock需要手动加锁解锁,但是性能较好
import java.util.concurrent.locks.ReentrantLock;
//使用多线程从10开始倒数到1
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2 = new TestLock2();
new Thread(testLock2,"线程1").start();
new Thread(testLock2,"线程2").start();
new Thread(testLock2,"线程3").start();
}
}
class TestLock2 implements Runnable {
int ticket_Num = 10;
//定义lock锁
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock(); //加锁
try{
if(ticket_Num > 0){
try {
//模拟延时
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//倒计时
System.out.println(ticket_Num--);
}else{
break;
}
}finally{
lock.unlock(); //解锁
}
}
}
}