一.线程同步机制

1.三大不安全案例

1.买票,多个线程共同使用票数
2.银行,两个人取同一个账户的钱
3.不能保证线程同步的集合

2.synchronized的同步方法及方法块

1.买票

package syn;

//不安全的买票
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();

        new Thread(buyTicket,"me").start();
        new Thread(buyTicket,"you").start();
        new Thread(buyTicket,"other").start();
    }
}

class BuyTicket implements  Runnable{

    int ticketNums = 100;
    boolean flag = true;
    @Override
    public void run() {
        //买票
        while(flag){
            //模拟延时
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            buy();
        }
    }
    //synchronized同步方法,锁的是this
    private synchronized void buy(){
        //判断是否有票
        if(ticketNums<=0){
            flag = false;
            return ;
        }

        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }

}

2.银行,不能直接锁run方法,因为run方法的this是银行,而不是账户,锁了银行,两个人仍可以从不同的银行,取同一个账户的钱,导致并发问题,可以锁方法块来解决

package syn;

public class UnSafeBank {

    public static void main(String[] args) {
        Account account = new Account(100, "MONEY");

        Drawing you = new Drawing(account,50,"你");
        Drawing me = new Drawing(account,100,"我");

        you.start();
        me.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 ;
            }

            //sleep可以放大问题的发生性
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            account.money = account.money - drawingMoney;

            nowMoney = nowMoney + drawingMoney;

            System.out.println(account.name+"余额为"+account.money);
            System.out.println(this.getName()+"手里的钱"+nowMoney);
        }
    }
}

juc安全类型的集合

package syn;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

import java.util.concurrent.CopyOnWriteArrayList;

//测试JUC安全类型的集合
public class TestJUC {

    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 100000; i++) {
            new Thread(() -> {
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

死锁

条件:互斥,不可抢占,循环等待,请求和保持

package DeadLock;

//死锁:多个线程互相只有对方需要的资源,形成僵持
public class DeadLock {

    public static void main(String[] args) {
        Makeup g1 = new Makeup(0,"xiao");
        Makeup g2 = new Makeup(1,"da");


        g1.start();
        g2.start();

    }

}

class Lipstick{

}

class Mirror{

}

class Makeup extends Thread{

    //需要的资源只有一份,用static来保证互斥条件
    static  Lipstick lipstick =new Lipstick();
    static  Mirror mirror =new Mirror();

    int choice; //选择
    String  girlName; //使用化妆品的人

    Makeup(int choice , String girlName){
        this.choice = choice;
        this.girlName = girlName;
    }

    @Override
    public void run(){
        //化妆
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //化妆,互相持有对方的锁,需要拿到对方的资源
    //满足了请求和保持,循环等待,不可抢占
    //想要解决死锁,只需要在请求新资源的时候吧旧的资源的锁释放掉就可一了
    private void makeup() throws InterruptedException {
        if(choice==0){
            synchronized (lipstick){ //获得口红的锁
                System.out.println(this.girlName+"获得口红的锁");
                Thread.sleep(1000);
                //一秒钟后想获得镜子
                synchronized (mirror){
                    System.out.println(this.girlName+"获得镜子的锁");
                }
            }
        }
        else{
            synchronized (mirror){
                System.out.println(this.girlName+"获得镜子的锁");
                Thread.sleep(2000);
                synchronized (lipstick){ //获得口红的锁
                    System.out.println(this.girlName+"获得口红的锁");
                }
            }
        }
    }

}

lock锁

不能同步方法,juc
与syn对比
1.syn是隐式的,自动释放,lock是显式的
2.lock只有代码块锁
3.lock性能好

package advanced;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {

    public static void main(String[] args) {
        TestLock2 testLock2 = new TestLock2();

        new Thread(testLock2).start();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
    }

}

class TestLock2 implements  Runnable{

    int ticketNums = 10;

    //定义lock锁
    private final ReentrantLock lock = new ReentrantLock();


    @Override
    public void run() {
        while(true){
            try{
                lock.lock();
                if(ticketNums>0){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(ticketNums--);
                }else{
                    break;
                }
            }finally{
                lock.unlock();
            }
        }
    }
}

生产者消费者问题

wait释放锁,常用来线程通信
noitfyALL唤醒所有线程
生产者消费者问题中用while而不用if,排除假唤醒
###管程法

package advanced;

//测试生产者消费者模型->利用缓冲区解决:管程法
//生产者,消费者,缓冲区
public class TestPC {
    public static void main(String[] args) {

        SynContainer container = new SynContainer();
        new Productor(container).start();
        new Consumer(container).start();

    }
}

class Productor extends  Thread{
    SynContainer container;

    public Productor(SynContainer container){
        this.container = container;
    }

    //生产
    @Override
    public void run(){
        for (int i = 0; i < 100; i++) {
            container.push(new Chicken(i));
        }
    }

}

class Consumer extends  Thread{
    SynContainer container;

    public Consumer(SynContainer container){
        this.container = container;
    }

    @Override
    public void run(){
        for (int i = 0; i < 100; i++) {
            container.pop();

        }
    }

}

class Chicken{
    int id;

    public Chicken(int id) {
        this.id = id;
    }
}

//缓冲区
class SynContainer{

    //容器大小
    Chicken[] chickens = new Chicken[10];
    //计数器
    int count = 0;

    //生产者丢入产品
    public synchronized  void push(Chicken chiken){
        //如果容器慢了就需要等待消费者消费
        while(count == 10){
            //通知消费者消费,生产者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果没有满就需要丢入产品

        chickens[count] = chiken;
        count++;
        System.out.println("生产了"+chiken.id+"只鸡");

        //可以通知消费者消费了
        this.notifyAll();
    }

    //消费者消费产品
    public synchronized Chicken pop(){
        while(count == 0){
            //等待生产者生产,消费者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //如果可以消费
        count--;
        Chicken chicken = chickens[count];
        System.out.println("消费了"+chicken.id+"只鸡");

        this.notifyAll();

        return chicken;
    }

}

信号灯法

package advanced;


//测试生产者消费者问题2:信号灯法
public class TestPC2 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}

//生产者--演员
class Player extends Thread{
    TV tv;
    public Player(TV tv){
        this.tv = tv;
    }

    @Override
    public void run(){
        for (int i = 0; i < 20; i++) {
            if(i%2 == 0){
                this.tv.play("haha");
            }else{
                this.tv.play("hehe");
            }
        }
    }

}

//消费者--观众
class Watcher extends Thread{

    TV tv;
    public Watcher(TV tv){
        this.tv = tv;
    }

    @Override
    public void run(){
        for (int i = 0; i < 20; i++) {
           tv.watch();
        }
    }

}

//产品
class TV{
    //演员表演,观众等待
    //观众观看,演员等待
    String voice; //表演的节目
    boolean flag = true;

    //表演
    public synchronized void play(String voice){
        while(flag==false){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演员表演了:"+voice);
        this.notifyAll();
        this.voice = voice;
        this.flag = !this.flag;

    }


    //观看
    public synchronized void watch(){
        while(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观看了:"+voice);
        //通知演员表演
        this.notifyAll();
        this.flag = !this.flag;
    }

}

线程池

package advanced;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestPool {

    public static void main(String[] args) {
        //1.创建服务,创建线程池,参数为线程池大小
        ExecutorService ser = Executors.newFixedThreadPool(10);

        ser.execute(new MyThread());
        ser.execute(new MyThread());
        ser.execute(new MyThread());

        ser.shutdown();

    }

}

class MyThread implements Runnable{

    @Override
    public void run() {
            System.out.println(Thread.currentThread().getName());
    }
}