线程同步3

线程同步

并发 同一对象被多个线程同时操作

线程同步:

处理多线程问题时,多线程访问同一个对象,并且某些线程还想修改这个对象,这时候我们就需要线程同步,线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕1,下一个线程在使用

三大安全案例

//不安全取钱
package test1;
//不安全取钱
public class Demo2 {
    public static void main(String[] args) {
        Account sang = new Account("sang", 1000);
        Bank bank = new Bank(sang,500,"me");
        Bank bank1 = new Bank(sang,900,"other");
        bank.start();
        bank1.start();


    }
}
//账户
class Account {
    private String name;//账户名
    private int money;//账户余额
    public Account() {
    }
    public Account(String name, int money) {
        this.name = name;
        this.money = money;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setMoney(int money){
        this.money = money;
}
    public int getMoney() {
        return money;
    }
}

//银行模拟取款
class Bank extends Thread{
    Account account;//
    private int gotoOut;

    public Bank() {
    }
    public Bank(Account account, int gotoOut,String name) {
        super(name);
        this.account = account;
        this.gotoOut = gotoOut;
    }
    @Override
    public void run() {
        int remainder = account.getMoney() - this.gotoOut;
        if (this.gotoOut>account.getMoney()){
            System.out.println(Thread.currentThread().getName() + "钱不够,请重新输入取款金额!");
            return;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
            account.setMoney(remainder);
            System.out.println(account.getName() + "Bank金额剩余:" + account.getMoney());
            System.out.println(Thread.currentThread().getName() + "取款" + account.getMoney());



    }

    public int getGotoOut() {
        return gotoOut;
    }

    public void setGotoOut(int gotoOut) {
        this.gotoOut = gotoOut;
    }
}
package test1;
//不安全买票,线程不安全有负数
public class Demo1 {
    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 TicketNum = 20;//票数
    boolean flag = true;
    @Override
    public void run() {
        while (flag){//外部停止方式
            try {
                Thread.sleep(100);
                buy();
                if (TicketNum <= 1){
                    flag = false;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void buy(){
        System.out.println(Thread.currentThread().getName()
        + "买了"+ this.TicketNum--);
    }
}
package test1;

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

//线程不安全的集合
public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{list.add(Thread.currentThread().getName());}).start();
        }
        Thread.sleep(1000);
        System.out.println(list.size());//7219
    }
}

同步方法

同步块

package test1;

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

//线程不安全的集合
public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized (list) {
                    list.add(Thread.currentThread().getName());
                }}).start();
        }
        Thread.sleep(1000);
        System.out.println(list.size());//7219
    }
}

//synchronized默认锁定是this.
    @Override
    public void run() {
        //锁的对象就是变化的量,需要增删改的对象
        synchronized (account){
            int remainder = account.getMoney() - this.gotoOut;
            //判断钱够不够
            if (this.gotoOut>account.getMoney()){
                System.out.println(Thread.currentThread().getName() + "钱不够,请重新输入取款金额!");
                return;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.setMoney(remainder);
            System.out.println(account.getName() + "Bank金额剩余:" + account.getMoney());
            System.out.println(Thread.currentThread().getName() + "取款" + account.getMoney());
        }
    }
 //synchronized同步关键字,锁的是this,对象
    private synchronized void buy(){
        System.out.println(Thread.currentThread().getName()
        + "买了"+ this.TicketNum--);
    }

疑问,juc安全类型的集合

package test1;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
//线程安全的集合类
public class TestJUC {
    public static void main(String[] args) throws InterruptedException {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }//有点疑惑,如果不加sleep类,还是不到10000,添加sleep后
        Thread.sleep(1000);//不到1000毫秒也不会到10000
        System.out.println(list.size());
    }
}

死锁

package test1;
//多线程互相需要对方锁内的资源,形成僵持,成为死锁
public class DeadLock {
    public static void main(String[] args) {
new MakeEat(0,"sang").start();
new MakeEat(1,"zhang").start();
    }
}
//曲奇饼
class Cookie{

}
//饼干,烤饼
class Biscuit{

}
class MakeEat extends Thread{
    int choose;
    String name;
    static Cookie cookie = new Cookie();//静态变量,只有一个,如果不是静态
    static Biscuit biscuit = new Biscuit();//这不会出现死锁现象
    @Override
    public void run() {
        //吃饼干
        try {
            eat();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    MakeEat(int choose,String name){
        this.choose = choose;
        this.name = name;
    }
    private void eat() throws InterruptedException {
        if (choose == 0){//先吃曲奇饼在吃饼干
            synchronized (cookie){
                System.out.println("吃曲奇饼" + this.name);
                Thread.sleep(3000);//多一会,保证出现死锁
                synchronized (biscuit){
                    System.out.println("吃饼干" + this.name);
                    Thread.sleep(1000);
                }
            }
//解决只需将synchronized放出来一个即可
        }else {
            synchronized (biscuit){
                System.out.println("吃饼干" + this.name);
                Thread.sleep(1000);
                synchronized (cookie){
                    System.out.println("吃曲奇饼" + this.name);
                    Thread.sleep(1000);
                }
            }

        }
    }
}

解决

 private void eat() throws InterruptedException {
        if (choose == 0){//先吃曲奇饼在吃饼干
            synchronized (cookie){
                System.out.println("吃曲奇饼" + this.name);
                Thread.sleep(3000);//多一会,保证出现死锁
            }
            synchronized (biscuit){
                System.out.println("吃饼干" + this.name);
                Thread.sleep(1000);
            }
//解决只需将synchronized放出来一个即可
        }else {
            synchronized (biscuit){
                System.out.println("吃饼干" + this.name);
                Thread.sleep(1000);
            }
            synchronized (cookie){
                System.out.println("吃曲奇饼" + this.name);
                Thread.sleep(1000);
            }
        }

死锁避免方法

Lock(锁)

ReentrantLock类实现了Lock,它拥有了与synchronized相同的并发性和内存语义,再实现线程安全控制中,比较常用的是ReentrantLock,可以显示加锁、释放锁。

package test1;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {
    public static void main(String[] args) {
        TestLock1 testLock1 = new TestLock1();
        new Thread(testLock1).start();
        new Thread(testLock1).start();
        new Thread(testLock1).start();
    }
}
class TestLock1 implements Runnable{
    private int testNum = 20;
    private final ReentrantLock reentrantLock = new ReentrantLock();
    @Override
    public void run() {
        reentrantLock.lock();
        try {
            while(this.testNum > 0){
                Thread.sleep(100);
                System.out.println(this.testNum--);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            reentrantLock.unlock();
        }
    }
}

synchronized与Lock的对比

posted @ 2023-01-06 17:47  小国哥哥  阅读(13)  评论(0编辑  收藏  举报