javase-thread-210313-01

javase-thread-210313-01

  • 线程同步
  • 死锁
  • Lock
  • 线程通信
    • 生产者/消费者模式01(管城法)
    • 生产者/消费者模式02(信号灯法)
  • 线程池

线程同步

关键字  synchronized

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

Demo01
public class Demo08_ThreadUnsafe01 {
    public static void main(String[] args) {
        Station station = new Station();
        new Thread(station,"路人A").start();
        new Thread(station,"路人B").start();
        new Thread(station,"路人C").start();
    }
}

class Station implements Runnable{
    private int ticket = 100;
    boolean flag = true;

    @Override
    public void run() {
        while (flag){
            buyTicket();
        }
    }

    // 同步方法
    // 加上synchronized变成同步方法    现在锁的this     默认对象是this
    private synchronized void buyTicket(){
        if(ticket <= 0){
            System.out.println("票已卖完");
            flag = false;
            return;
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "拿到了第" + ticket-- +"张票");
    }
}

Demo02
public class Demo08_ThreadUnsafe02 {
    public static void main(String[] args) {
        Account account = new Account(150,"bgy");
        new Thread(new Bank(0,50,account),"A").start();
        new Thread(new Bank(0,150,account),"B").start();
        new Thread(new Bank(0,150,account),"C").start();
        new Thread(new Bank(0,150,account),"D").start();
    }
}

class Account{
    int sumMoney;
    String name;

    public Account(int sumMoney, String name) {
        this.sumMoney = sumMoney;
        this.name = name;
    }
}

class Bank implements Runnable{

    Account account;
    int nowMoney;
    int drawMoney;

    public Bank(int nowMoney,int drawMoney,Account account){
        this.nowMoney = nowMoney;
        this.drawMoney = drawMoney;
        this.account = account;
    }

    @Override
    public void run() {

        //  同步块,可以监视任何对象
        //  锁的对象就是变化的量,,,所以这个例子要锁住account,而不是Bank
        synchronized (account){
            if(account.sumMoney <= drawMoney){
                System.out.println("余额不足");
                return;
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 取钱
            account.sumMoney = account.sumMoney - drawMoney;
            System.out.println("还剩余额"+account.sumMoney);

            // 目前我有多少钱
            nowMoney = nowMoney + drawMoney;
            System.out.println(Thread.currentThread().getName() + "我现在手里有" + nowMoney);
        }
    }

Demo03

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

public class Demo08_ThreadUnsafe03 {
    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());
    }
}

CopyOnWriteArrayList
CopyOnWriteArrayList   是一个线程安全的集合
import java.util.concurrent.CopyOnWriteArrayList;

public class Demo01 {
    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();
        }

        Thread.sleep(3000);

        System.out.println(list.size());
    }
}

死锁

产生死锁的四个条件:
	1. 互斥条件:一个资源每次只能被一个进程使用
	2. 请求与保持条件:一个进程因请求资源而阻塞是,对已获得的资源保持不放
	3. 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
	4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
	
只要破坏以上任意一个或多个条件就能避免死锁的发生
	

Demo01(造成死锁)
public class Demo01_DeadLock01 {
    public static void main(String[] args) {
        new GoOut(1,"路人甲").start();
        new GoOut(0,"路人乙").start();
    }
}

// 需要穿的衣服
class Cloth{ }

// 需要穿的鞋子
class Shoes{ }

//  选择搭配
class GoOut extends Thread{

    // static修饰,,确保只有一件衣服,一双鞋子
    static Cloth cloth = new Cloth();
    static Shoes shoes = new Shoes();

    int choose;
    String userName;

    public GoOut(int choose, String userName) {
        this.choose = choose;
        this.userName = userName;
    }

    @Override
    public void run() {
        try {
            makeUp();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 穿搭
    public void makeUp() throws InterruptedException {

        /*
            目前情况会造成死锁,,双方都拿着锁,都不释放锁
        */

        if (choose == 1){
            synchronized (cloth){       // 得到衣服的锁
                System.out.println(this.userName+"获得衣服的锁");

                Thread.sleep(1000);

                synchronized (shoes){       // 得到鞋子的锁
                    System.out.println(this.userName+"获得鞋子的锁");
                }
            }

        }else{
            synchronized (shoes){       // 得到鞋子的锁
                System.out.println(this.userName+"获得鞋子的锁");

                Thread.sleep(1000);

                synchronized (cloth){       // 得到衣服的锁
                    System.out.println(this.userName+"获得衣服的锁");
                }
            }
        }
    }
}

Demo02(解决)

public class Demo01_DeadLock02 {
    public static void main(String[] args) {
        new GoOut02(1,"路人甲").start();
        new GoOut02(0,"路人乙").start();
    }
}

// 需要穿的衣服
class Cloth02{ }

// 需要穿的鞋子
class Shoes02{ }

//  选择搭配
class GoOut02 extends Thread{

    // static修饰,,确保只有一件衣服,一双鞋子
    static Cloth cloth = new Cloth();
    static Shoes shoes = new Shoes();

    int choose;
    String userName;

    public GoOut02(int choose, String userName) {
        this.choose = choose;
        this.userName = userName;
    }

    @Override
    public void run() {
        try {
            makeUp();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 穿搭
    public void makeUp() throws InterruptedException {

        /*
            解决死锁
        */

        if (choose == 1){
            synchronized (cloth){       // 得到衣服的锁       sleep方法不会释放锁,,同步代码块结束后释放锁
                System.out.println(this.userName+"获得衣服的锁");

                Thread.sleep(1000);
            }

            // 放到外面
            synchronized (shoes){       // 得到鞋子的锁
                System.out.println(this.userName+"获得鞋子的锁");
            }

        }else{
            synchronized (shoes){       // 得到鞋子的锁
                System.out.println(this.userName+"获得鞋子的锁");

                Thread.sleep(1000);
            }

            // 放到外面
            synchronized (cloth){       // 得到衣服的锁
                System.out.println(this.userName+"获得衣服的锁");
            }
        }
    }
}

Lock

	Lock是显示锁(手动开启关闭锁),,,synchronized是隐式锁,出了作用域自动释放
	
	Lock只有代码块锁,,synchronized有代码块锁和方法锁
	
	使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(拥有更多的子类)
	
	优先使用:
		Lock > 同步代码块 > 同步方法
		同步代码块:已经进入到了方法体,分配了相应的资源
		同步方法:在方法体之外
Demo
import java.util.concurrent.locks.ReentrantLock;

public class Demo02_Lock implements Runnable{
    private int ticket = 100;
    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        getTicket();
    }

    public void getTicket() {
        while (true){
            try{
                // 加锁
                lock.lock();

                if(ticket <= 0){
                    System.out.println("票已售空");
                    break;
                }

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "获得第" + ticket-- +"张票");
            }finally {
                // 解锁
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        Demo02_Lock demo = new Demo02_Lock();
        new Thread(demo,"线程A").start();
        new Thread(demo,"线程B").start();
    }
}

线程通信

	wait()		
		表示线程一直等待,直到其他线程通知,与slee相反,会释放锁
	
	wait(long time)
    	指定等待的毫秒数
    	
	notify()
		唤醒一个处于等待状态的线程
		
	notifyAll()
		唤醒同一个对象上所有调用wait方法的程,优先级别高的线程优先调用
		
以上均为Object类的方法,都只能用在同步方法或同步代码块中,
否则抛出lllegaMonitorStateException
01生产者/消费者模式(管城法)
	生产者/消费者模式 ,,也叫,,管城法
	
	生产者:负责生产数据的模块(可以是方法,对象,线程,进程)
	消费者:负责处理数据的模块(可以是方法,对象,线程,进程)
	缓冲区:消费者不能直接使用生产者的数据,他们之间有一个“缓冲区”
	
	生产者将生产好的数据放入缓冲区,,,消费者从缓冲区拿取数据
public class Demo03_PC01 {
    public static void main(String[] args) {
        Container container = new Container();
        new Consumer(container).start();
        new Product(container).start();
    }
}

// 定义产品
class Chicken{
    int id;

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

// 1.定义容器
class Container{

    // 定义容器大小
    Chicken[] chickens = new Chicken[10];

    // 定义容器计数器
    int count = 0;

    // 生产者放入产品
    public synchronized void push(Chicken chicken){
        // 判断容器是否满了,,满的话就等待消费者消费
        if (count == chickens.length){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 没满的话,放入产品
        chickens[count]=chicken;
        count++;

        // 这个用来通知消费者消费
        this.notifyAll();
    }

    // 消费者消费产品
    public synchronized Chicken pop(){
        // 判断容器是否是空,,空的话就等待生产者生产
        if (count == 0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 满的话,消费产品
        count--;
        Chicken chicken = chickens[count];

        // 买完了,通知生产者生产
        this.notifyAll();

        return chicken;
    }
}

// 消费者
class Consumer extends Thread{
    Container containe;

    public Consumer(Container containe){
        this.containe = containe;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了" + containe.pop().id + "只鸡");
        }
    }
}

// 生产者
class Product extends Thread{
    Container containe;

    public Product(Container containe){
        this.containe = containe;
    }

    @Override
    public void run() {
        for (int i = 1; i < 101; i++) {
            System.out.println("生产了" + i + "只鸡");
            containe.push(new Chicken(i));
        }
    }
}
02生产者/消费者模式(信号灯法)
public class Demo03_PC02 {
    public static void main(String[] args) {
        TV tv = new TV();
        new PeoplePlay(tv).start();
        new PeopleWatch(tv).start();
    }
}

// 创建一个动漫
class TV{
    /*
        规则如下:
            演员表演,观众等待   T
            观众观看,演员等待   F

        不是直播,是录播
    */

    // 节目
    String program;
    // 标志
    boolean flag = true;

    // 表演
    public synchronized void play(String program){

        // 如果为false,,观众观看,演员等待
        if (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("现在的节目是:" + program);

        // 通知观众观看
        this.notifyAll();

        this.program = program;

        this.flag = !this.flag;
    }

    // true,,观众等待,演员表演
    public synchronized void watch(){
        if (flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("观众正在看:" + program);

        this.notifyAll();
        this.flag = !this.flag;
    }
}

// 表演的人
class PeoplePlay extends Thread{
    TV tv;
    public PeoplePlay(TV tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i%2 == 0){
                this.tv.play("斗罗大陆");
            }else{
                this.tv.play("化肥就用史丹利!!!!");
            }
        }
    }
}

// 观看的人
class PeopleWatch extends Thread{
    TV tv;
    public PeopleWatch(TV tv){
        this.tv = tv;
    }

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

线程池


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

public class Demo04_ThreadPool {
    public static void main(String[] args) {

        // 创建线程池
        // newFixedThreadPool  池子大小
        ExecutorService service = Executors.newFixedThreadPool(10);

        TestThread tt = new TestThread();
        service.execute(tt);
        service.execute(tt);
        service.execute(tt);
        service.execute(tt);

        // 关闭连接
        service.shutdown();

    }
}

class TestThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值