并发:同一个对象被多个线程同时操作
模拟买票
package mii.thread.demo05多线程问题;
/**
* 多线程同时操作一个对象
* 买火车票例子
* 【问题:多个线程操作同一资源,线程不安全,数据紊乱】
*/
public class TestRunnable implements Runnable {
// 票数
private int ticketNum = 10;
public void run() {
while(ticketNum > 0){
System.out.println(Thread.currentThread().getName() +
"-->买到了第 " + ticketNum-- + " 张票!");
// 模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
TestRunnable tt = new TestRunnable();
new Thread(tt, "小明").start();
new Thread(tt, "小红").start();
new Thread(tt, "小刚").start();
}
}
▼处理多线程问题:
多个线程同时访问并修改同一个对象,这时就需要线程同步。线程同步就是一种等待机制,多个同时需要访问此对象的线程进入这个对象的
对象等待池
形成队列,等待前面线程访问完毕,下一个线程再访问。▼锁机制:
由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制
synchronized
,当一个线程获得对象的排它锁,独占资源,其他线程必须等待使用后释放锁即可。▼存在以下问题:
- 一个线程持有锁会导致其他所有需要此锁的线程挂起(性能损失)
- 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题
- 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题
▼synchronized
- synchronized 方法
synchronized void method(){...}
- synchronized 块(块内必须是引用)
synchronized (obj){...}
▼synchronized 修饰的称为
同步监视器
,修饰方法时同步监视器就是this,当前对象本身
package mii.thread.demo13线程同步;
public class UnsafeBuyTicket implements Runnable {
private int ticketNum = 10; // 票数
public void run() {
while(true){
try {
boolean buy = buy();
if(!buy){
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// synchronized 同步方法
private synchronized boolean buy() throws InterruptedException {
// 模拟延时
Thread.sleep(100);
if(ticketNum > 0){
System.out.println(Thread.currentThread().getName() +
"-->买到了第 " + ticketNum-- + " 张票!,还剩" +
ticketNum + "张票...");
return true;
}else{
System.out.println(Thread.currentThread().getName() +
"手慢了,购票失败!");
return false;
}
}
public static void main(String[] args) {
UnsafeBuyTicket tt = new UnsafeBuyTicket();
new Thread(tt, "小明").start();
new Thread(tt, "小红").start();
new Thread(tt, "小刚").start();
}
}
package mii.thread.demo13线程同步;
public class UnsafeBuyTicket implements Runnable {
private Integer ticketNum = 10; // 票数
public void run() {
while(true){
try {
// 模拟延时
Thread.sleep(100);
synchronized (ticketNum){
if(ticketNum > 0){
System.out.println(Thread.currentThread().getName() +
"-->买到了第 " + ticketNum-- + " 张票!,还剩" +
ticketNum + "张票...");
}else{
System.out.println(Thread.currentThread().getName() +
"手慢了,购票失败!");
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
UnsafeBuyTicket tt = new UnsafeBuyTicket();
new Thread(tt, "小明").start();
new Thread(tt, "小红").start();
new Thread(tt, "小刚").start();
}
}