线程同步: 模拟售票程序出现问题: 当多个线程同时访问共享数据时,产生无序、重复、超额售票等多线程安全问题 解决:将多个线程需要访问的共享数据,包装起来视为一个整体,确保一次只有一个线程执行流访问共享数据 Java为上述问题提供了相应的解决办法: 1、同步代码块 synchronized(同步监视器){ //多个线程需要访问的共享数据 } 同步监视器:俗称“锁” ,可以使用任意类型的对象充当。但是必须保证多个线程持有 同一把锁(同一个对象) 2、同步方法 3、同步锁 Lock
package Thread;
public class TicketWindow2 implements Runnable{
int tick=100;
Object obj=new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if (tick>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()+"完成售票,剩余票数:"+ --tick);
}
}
}
}
}
package Thread;
public class TicketWindowTest2 {
public static void main(String[] args) {
TicketWindow2 tw2=new TicketWindow2();
Thread t1=new Thread(tw2,"一号窗口");
t1.start();
Thread t2=new Thread(tw2,"二号窗口");
t2.start();
Thread t3=new Thread(tw2,"三号窗口");
t3.start();
}
}
同步方法 :
在方法声明处加 synchronized 关键字 如: public synchronized void show() { }
package Thread;
public class TicketWindow2 implements Runnable{
int tick=100;
Object obj=new Object();
@Override
public void run() {
while (true){
/* synchronized (obj){
if (tick>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()+"完成售票,剩余票数:"+ --tick);
}
}*/
show();
}
}
public synchronized void show(){
if (tick>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()+"完成售票,剩余票数:"+ --tick);
}
}
}
同步锁:
Lock为接口,创建实例
unlock一定要执行,所以放到try-catch-finally中
package Thread;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TicketWindow2 implements Runnable{
int tick=100;
Object obj=new Object();
Lock l=new ReentrantLock();
@Override
public void run() {
while (true){
/* synchronized (obj){
if (tick>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()+"完成售票,剩余票数:"+ --tick);
}
}*/
// show();
l.lock();//上锁
try {
if (tick>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()+"完成售票,剩余票数:"+ --tick);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
l.unlock();//释放锁
}
}
}
public synchronized void show(){
if (tick>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()+"完成售票,剩余票数:"+ --tick);
}
}
}
当前的锁为悲观锁
线程同步: 模拟售票程序出现问题: 当多个线程同时访问共享数据时,产生无序、重复、超额售票等多线程安全问题 解决:将多个线程需要访问的共享数据,包装起来视为一个整体,确保一次只有一个线程执行流访问共享数据 Java为上述问题提供了相应的解决办法: 1、同步代码块 synchronized(同步监视器){ //多个线程需要访问的共享数据 } 同步监视器:俗称“锁” ,可以使用任意类型的对象充当。但是必须保证多个线程持有 同一把锁(同一个对象) 2、同步方法:在方法声明处加 synchronized 关键字 如: public synchronized void show() { } 注意:非静态同步方法隐式的锁为 this(即当前对象) 静态同步方法的锁为对应类的Class实例 3、同步锁 Lock
Exer:
银行有一个账户。 有两个储户分别向同一个账户存3000元,每次存1000,存3次。每次存完打印账户余额. 问题:该程序是否有安全问题,如果有,如何解决? 【提示】 1,明确哪些代码是多线程运行代码,须写入run()方法 2,明确什么是共享数据。 3,明确多线程运行代码中哪些语句是操作共享数据的。
package Exer;
/*
银行有一个账户。
有两个储户分别向同一个账户存3000元,每次存1000,存3次。每次存完打印账户余额.
问题:该程序是否有安全问题,如果有,如何解决?
【提示】
1,明确哪些代码是多线程运行代码,须写入run()方法
2,明确什么是共享数据。|
3,明确多线程运行代码中哪些语句是操作共享数据的。
*/
public class Exer {
public static void main(String[] args) {
Account account=new Account();
Customer ca=new Customer(account);
Customer cb=new Customer(account);
new Thread(ca,"用户A").start();
new Thread(cb,"用户B").start();
}
}
package Exer;
public class Account {
private double balance;
public Account() {
}
public Account(double balance) {
this.balance = balance;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
//存款
public synchronized void deposit(double amount){
balance+=amount;
System.out.println(Thread.currentThread().getName()+"成功存入:"+amount+"余额为:"+balance);
}
}
package Exer;
public class Customer implements Runnable {
private Account account;
public Customer() {
}
public Customer(Account account) {
this.account = account;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
@Override
public void run() {
for (int i = 0; i <3; i++) {
account.deposit(1000);
}
}
}
补充:互斥锁
线程的死锁问题:
package Thread;
public class DeadLockTest {
public static void main(String[] args) {
DeadLock dl=new DeadLock();
new Thread(dl).start();
new Thread(dl).start();
}
}
class DeadLock implements Runnable{
boolean flag=true;
static Object obj1=new Object();//共享数据1
static Object obj2=new Object();//共享数据2
@Override
public void run() {
if (flag){
synchronized (obj1){
System.out.println("获取共享数据1,等待共享数据2....");
synchronized (obj2){
System.out.println("-----------------------");
}
}
}else {
synchronized (obj2){
System.out.println("获取共享数据2,等待共享数据1....");
synchronized (obj1){
System.out.println("*************************");
}
}
}
}
}
------------------------------------------------------------------------------------------------------------
将问题放大: