2021-10-24(java-多线程2)

目录

1.线程休眠:(sleep)

2.线程礼让:(yield)

3.线程强行停止:(join)

4.线程状态,线程可以处于以下状态之一:(Thread.State)

5.线程优先级:

6.守护线程:

7.线程同步:

三大不安全案例   (sleep)方法问题的发生性

同步方法:(会影响效率)锁的是this

8.死锁(多个线程互相抱着对方的资源,然后停止)

9.Lock:(ReentrantLock) 

10.生产者消费者:


1.线程休眠:(sleep)

         sleep(时间)指定当前线程阻塞的毫秒数;
    sleep 存在异常InterruptedException;
    sleep 时间达到后线程进入就绪状态
    sleep 可以模拟网络延时,倒计时等。
    每一个对象都有一个锁,sleep不会释放锁

/*模拟网络延迟:放大问题的发生性*/
public class TestSleep implements Runnable {
    //票数
    private int ticketNums = 10;

    @Override
    public void run() {
        while (true) {
            if (ticketNums <= 0) {
                break;
            }
            //模拟延时
            try {
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "--->拿到了第" + ticketNums-- + "票");
        }

    }

    public static void main(String[] args) {
        TestSleep testSleep = new TestSleep();

        new Thread(testSleep,"小明").start();
        new Thread(testSleep,"小红").start();
        new Thread(testSleep,"小黄牛").start();

    }
}
///模拟倒计时

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestSleep2 {

    public static void testDown() throws InterruptedException {
        int num = 10;
        while (true) {
            Thread.sleep(1000);
            System.out.println(num--);
            if (num == 0) {
                break;
            }
        }
    }

    /**
     * 打印当前时间
     */
    public static void printNowDate() {
        //打印当前系统时间
        Date stattTime = new Date(System.currentTimeMillis());
        while (true) {
            try {
                //休眠1秒
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(stattTime));     //格式化时间,并输出时间
                stattTime = new Date(System.currentTimeMillis());       //更新获取时间
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) {
        printNowDate();
    }
}

2.线程礼让:(yield)

       1.礼让线程,让当前正在执行的线程暂停,但不阻塞
  2.将线程从运行状态转为就绪状态
  3.让cpu 重新调度,礼让不一定成功!看cpu

public class TestYield {
    public static void main(String[] args) {
        MyYield myYield = new MyYield();

        new Thread(myYield,"A").start();
        new Thread(myYield,"B").start();

    }
}


class MyYield implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程开始执行");
        Thread.yield();//礼让
        System.out.println(Thread.currentThread().getName()+"线程停止执行");
    }

}

3.线程强行停止:(join)

Join 合并线程,待此线程执行完成后,再执行其他线程(想象为插队)

public class TestJoin implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("线程VIP 来了" + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        //启动线程
        thread.start();

        //主线程
        for (int i = 0; i < 200; i++) {
            if (i == 100) {
                thread.join();//插队
            }
            System.out.println("main" + i);
        }

    }
}

4.线程状态,线程可以处于以下状态之一:(Thread.State)


        NEW
          尚未启动的线程处于此状态
        RUNNABLE
          在Java虚拟机中执行的线程处于此状态
        BLOCKED
          被阻塞等待监视器锁定的线程处于此状态
        WAITING
          正在等待另一个线程执行特定动作的线程处于此状态
        TIMED WAITING
          正在等待另一个线程执行动作达到指定等待时间的线程处于此状态
        TERMINATED
          已退出的线程处于此状态

5.线程优先级:

        设置线程优先级:setPriority(1---10)      优先级高的获取cpu的概率大,不一定高的就先跑

        获取线程优先级:getPriority()        

6.守护线程:

thread.setDaemon(true);    //默认为false表示用户线程,正常线程都是用户线程

You线程执行完,God守护线程也会停止

package 多线程;
public class ThreadDaemon {
    public static void main(String[] args) {
        God god = new God();
        You you = new You();
        Thread thread=new Thread(god);
        thread.setDaemon(true);    //默认为false表示用户线程,正常线程都是用户线程
        thread.start();

        new Thread(you).start();     //用户线程
    }
}
class God implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("你好呀");
        }
    }
}
class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("你活了"+i);
        }
        System.out.println("没了");
    }
}

7.线程同步:

三大不安全案例   (sleep)方法问题的发生性

package 多线程.syn;

/**
 * 模拟买票
 * 线程不安全
 * 可能会出现-1
 *
 */
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        Buy buy = new Buy();

        Thread thread1=new Thread(buy,"小红");
        Thread thread2=new Thread(buy,"小明");
        Thread thread3=new Thread(buy,"小刚");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
class Buy implements Runnable{
    private int ticketNums=10;
    boolean flag=true;
    @Override
    public void run() {
        while (flag) {
            if(ticketNums<=0){
                flag=false;
                return;
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"第几章"+ticketNums--);
        }
    }
}
package 多线程.syn;

/**
 * 模拟银行取钱
 * 大于100都进去取钱
 * 导致超出取钱
 */

public class UnsafeBank {
    public static void main(String[] args) {
        Account account=new Account(100,"小明");
        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);                    //super必须在第一个
        this.account = account;
        this.drawingMoney = drawingMoney;
    }
//取钱
    @Override
    public void run() {
        //判断有没有钱
        if (account.money-drawingMoney<0){
            System.out.println(this.getName()+"钱不够");
            return;
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        account.money=account.money-drawingMoney;   //账户的钱
        nowMoney=nowMoney+drawingMoney;             //手里的钱
        System.out.println(account.name+"余额为:"+account.money);
        //Thread.currentThread().getName()==this.getName
        System.out.println(this.getName()+"手里的钱:"+nowMoney);

    }
}
package 多线程.syn;
/**
*用10000个线程打印10000个数据,导致数据少
*问题:两个线程同时操作一个位置,会覆盖不会增加
*/
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(2000);
        System.out.println(list.size());
    }
}

同步方法:(会影响效率)锁的是this

        在方法前加 :synchronized             排队

@Override
public void run() {
    while (flag) {
        mai();
    }
}
private synchronized void mai(){
    if(ticketNums<=0){
        flag=false;
        return;
    }
    try {
        Thread.sleep(10);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName()+"第几章"+ticketNums--);
}
锁的对象是变化的量,需要增删改查的,默认为this,
//取钱
    @Override
    public void run() {
        synchronized(account){
            //判断有没有钱
            if (account.money-drawingMoney<0){
                System.out.println(this.getName()+"钱不够");
                return;
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.money=account.money-drawingMoney;   //账户的钱
            nowMoney=nowMoney+drawingMoney;             //手里的钱
            System.out.println(account.name+"余额为:"+account.money);
            //Thread.currentThread().getName()==this.getName
            System.out.println(this.getName()+"手里的钱:"+nowMoney);

        }
不加sleep线程会提前跑完,还是不安全
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(()->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        Thread.sleep(2000);
        System.out.println(list.size());
    }
}

8.死锁(多个线程互相抱着对方的资源,然后停止)

public class TestLock {
    public static void main(String[] args) {
        Makeup g1 = new Makeup(0,"灰姑凉");
        Makeup g2 = new Makeup(1,"白雪公主");
        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;//使用化妆品的人
    public 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(100);

                synchronized (mirror) {//一秒钟后想获得镜子
                    System.out.println(this.girlName + "获得镜子的锁");
                }
            }
        } else {
            synchronized (mirror) {//想获得镜子的锁
                System.out.println(this.girlName + "获得镜子的锁");
                Thread.sleep(100);
                synchronized (lipstick) {//一秒钟后想获得口红
                    System.out.println(this.girlName + "获得口红的锁");
                }
            }
        }
    }
}

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

9.Lock:(ReentrantLock) 

        手动开关

import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
    public static void main(String[] args) {
        TestLock2 lock2 = new TestLock2();
        new Thread(lock2,"1").start();
        new Thread(lock2,"2").start();
        new Thread(lock2,"3").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(100);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" "+ticketNums--);
                }else {
                    break;
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();//解锁
            }
        }
    }
}

10.生产者消费者:

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 = 1; i <= 20; i++) {
            container.push(new Chiken(i));
            System.out.println("生产了"+i+"只鸡");
        }
    }
}

//消费者
class Consumer extends Thread {
    SynContainer container;

    public Consumer(SynContainer container) {
        this.container = container;
    }
    //生产
    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            Chiken pop = container.pop();
            System.out.println("消费了第"+pop.id+"只鸡");
        }
    }
}

//产品
class Chiken {
    int id;//编号

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

//缓冲区
class SynContainer {

    //需要一个容器大小
    Chiken[] chikens = new Chiken[10];
    //容器计数器
    int count = 0;

    //生产者放入产品
    public synchronized void push(Chiken chiken) {
        //如果容器满了,就需要等待消费者消费
        if (count == chikens.length) {
            //通知消费者消费,生产者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果容器没有满,我们就需要丢入产品
        chikens[count] = chiken;
        count++;
        //通知消费者消费
        this.notifyAll();     //唤醒
    }  

    //通知消费者消费
    public synchronized Chiken pop() {
        //判断能否消费
        if (count == 0) {
            //等待生产者生产,消费者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果可以消费
        count--;
        Chiken chiken = chikens[count];
        //吃完了,通知生产者生产
        this.notifyAll();       
        return chiken;
    }
}

おすすめ

転載: blog.csdn.net/qq_45688193/article/details/120943491
おすすめ