三人买票(不加synchronized)
package com.cyz.lock;
//不安全的买票
//线程不安全,会拿到同一张票
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket station = new BuyTicket();
new Thread(station,"我").start();
new Thread(station,"你").start();
new Thread(station,"黄牛").start();
}
}
//买票
class BuyTicket implements Runnable{
//票
private int ticketNum = 10;
boolean flag = true;//外部停止线程方式
@Override
public void run() {
//买票
while (flag){
try {
//模拟延时
Thread.sleep(100);
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//加了synchronized锁就线程同步了
private void buy() throws InterruptedException {
//判断是否有票
if(ticketNum<=0){
return;
}
//买票
System.out.println(Thread.currentThread().getName()+"买到"+ticketNum--);
}
}
运行结果
我们可以看到,多人买了同一张票。现实里根本不允许这样的存在。
三人买票(加了synchronized后,我们要锁的是buy()这个方法)
package com.cyz.lock;
//不安全的买票
//线程不安全,会拿到同一张票
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket station = new BuyTicket();
new Thread(station,"我").start();
new Thread(station,"你").start();
new Thread(station,"黄牛").start();
}
}
//买票
class BuyTicket implements Runnable{
//票
private int ticketNum = 10;
boolean flag = true;//外部停止线程方式
@Override
public void run() {
//买票
while (flag){
try {
//模拟延时
Thread.sleep(100);
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//加了synchronized锁就线程同步了
private synchronized void buy() throws InterruptedException {
//判断是否有票
if(ticketNum<=0){
return;
}
//买票
System.out.println(Thread.currentThread().getName()+"买到"+ticketNum--);
}
}
运行截图
注意!线程sleep要写在synchronized函数的外部,不然线程会带着锁休眠,别人的线程就无法执行,眼巴巴地等着这个线程从睡眠中醒来,继续执行,票全被这个线程拿走,像下面这样
两人对同一银行账户取钱(不加synchronized)
package com.cyz.lock;
//不安全的取钱
//两个人取同一张卡
public class UnsafeBank {
public static void main(String[] args) {
//账户
Account account = new Account(100, "结婚基金");
Drawing you = new Drawing(account, 50, "你");
Drawing girlfriend = new Drawing(account, 100, "女朋友");
you.start();
girlfriend.start();
}
}
//账户
class Account {
int money;//余额
String name;//卡名
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//银行:模拟取款
class Drawing extends Thread{
Account account;//账户
//取了多少钱
int drawingMoney;
//现在手里有多少钱
int nowMoney;
public Drawing(Account account, int drawingMoney, String name){
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
//取钱
@Override
public void run() {
//判断有无钱
if (account.money-drawingMoney<0){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡内余额 = 余额 - 你取的钱
account.money = account.money - drawingMoney;
//你手里的钱
nowMoney = nowMoney + drawingMoney;
System.out.println(account.name+"余额为:"+ account.money);
//Thread.currentThread().getName()和this.getName()是一个东西
System.out.println(this.getName()+"="+Thread.currentThread().getName()+"手里的钱:"+nowMoney);
}
}
运行结果
取得银行破产了
两人对同一银行账户取钱(加synchronized块,我们要锁的是银行账户这个对象,而不是取钱的人)
如果要锁取钱的人就无效
package com.cyz.lock;
//不安全的取钱
//两个人取同一张卡
public class UnsafeBank {
public static void main(String[] args) {
//账户
Account account = new Account(100, "结婚基金");
Drawing you = new Drawing(account, 50, "你");
Drawing girlfriend = new Drawing(account, 100, "女朋友");
you.start();
girlfriend.start();
}
}
//账户
class Account {
int money;//余额
String name;//卡名
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//银行:模拟取款
class Drawing extends Thread{
Account account;//账户
//取了多少钱
int drawingMoney;
//现在手里有多少钱
int nowMoney;
public Drawing(Account account, int drawingMoney, String name){
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
//取钱
@Override
public void run() {
//锁银行这个账户
synchronized (account){
//判断有无钱
if (account.money-drawingMoney<0){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡内余额 = 余额 - 你取的钱
account.money = account.money - drawingMoney;
//你手里的钱
nowMoney = nowMoney + drawingMoney;
System.out.println(account.name+"余额为:"+ account.money);
//Thread.currentThread().getName()和this.getName()是一个东西
System.out.println(this.getName()+"="+Thread.currentThread().getName()+"手里的钱:"+nowMoney);
}
}
}
运行结果
我取完钱,女朋友再取,账户里没这么多钱就没法取了。
ArrayList也不安全
package com.cyz.lock;
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(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
运行结果
明明往里要填10000个线程的名字,结果只填了9997个。丢了丢了
ArrayList(加了synchronized块,线程立马老老实实排队,一个一个往里头进)
package com.cyz.lock;
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();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
运行截图
全了全了