多线程全部

多线程

  • 线程就是独立的执行路径
  • 在程序运行是,即使没有自己的创建线程,后台也会有多个线程,如主线程,GC线程
  • main()称之为主线程,为系统的入口,用于执行真个程序
  • 在一个进程中,如果开辟了多个线程,下城的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的
  • 对同一份资料操作时,会存在组员抢夺问题,需要加入并发控制
  • 线程会带来额外的开销。容易CPU调度时间,并发控制开销
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

创建线程

三种线程创建

  • Thread Class 继承Thread类 需要重写run方法

  • Runnable 接口 实现Runnable接口 需要重写run方法

  • Callable 接口 实现Callable接口 需要重写call方法

    1.继承Thread类 实现多线程创建

package Dem01;

//创建线程方式一:继承Thread类,重写run()方法,调用start 开启线程

//总结:注意,线程开启不一定立即执行,由CPU调度执行
public class TestThread01 extends Thread {
    //重写run方法
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 5; i++) {
            System.out.println("灰太狼来了---"+i);
        }
    }
    //main线程,主线程
    public static void main(String[] args) {
        //创建一个线程对象
        TestThread01 testThread01 = new TestThread01();
        //调用 start()方法 开启线程
        testThread01.start();

        for (int i = 0; i < 5; i++) {
            System.out.println("我一定会回来的---"+i);
        }
    }
}

练习多线程–网图下载

package Dem01;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

//练题Thread,实现多线程同步下载图片
public class TestThread02 extends Thread {

    private String url;//网络图片地址
    private String name;//保存的文件名

    public TestThread02(String url,String name){
        this.url = url;
        this.name = name;
    }
    @Override
    public void run() {
        super.run();
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
    }
    public static void main(String[] args) {
        TestThread02 t1 = new TestThread02("https://p5.ssl.qhimgs1.com/dmfd/128_96_80/t0119191d9915b1b3f5.webp","2.jpg");
        TestThread02 t2 = new TestThread02("https://p5.ssl.qhimgs1.com/dmfd/128_96_80/t0119191d9915b1b3f5.webp","2.jpg");
        TestThread02 t3 = new TestThread02("https://p5.ssl.qhimgs1.com/dmfd/128_96_80/t0119191d9915b1b3f5.webp","2.jpg");

        //本应先下载t1 之后t2然后t3  但是因为是同时运行的 所以下载顺序是不同的
        t1.start();
        t2.start();
        t3.start();
    }
}
//下载器
class WebDownloader{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出现问题");
        }
    }
}

实现Runnable接口

package Dem01;
//创建线程方式2:实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法
public class TestThread03 implements Runnable{
    @Override
    public void run() {
        //run方程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码---"+i);
        }
    }
    public static void main(String[] args) {
        //创建一个runnable接口的实现类对象
        TestThread03 testThread03 = new TestThread03();
        //创建线程对象,通过线程对象来开启我们的线程,代理
//        Thread thread = new Thread(testThread03);
//        thread.start();    这两句代码可以简写为下面的形式

        new Thread(testThread03).start();

        for (int i = 0; i < 50; i++) {
            System.out.println("我在学习多线程---"+i);
        }
    }
}

初识并发问题

package Dem01;
//多个线程同时操作同一个对象,
//买火车票的例子

//发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱
public class TestThread04 implements Runnable {
    //票数
    private  int ticketNums = 10;
    @Override
    public void run() {
        while (true){
            if (ticketNums<=0){
                break;
            }
            //模拟延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"票");
        }
    }
    public static void main(String[] args) {

        TestThread04 ticket = new TestThread04();

        new Thread(ticket,"小明").start();
        new Thread(ticket,"老师").start();
        new Thread(ticket,"黄牛党").start();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y6E9RSJE-1628778428795)(C:\Users\Administrator.USER-20190630SI\Desktop\并发问题结果图.jpg)]

练习:龟兔赛跑

package Dem01;
//模拟龟兔赛跑
public class Race implements Runnable   {
    //胜利者
    private static String Winner;

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

            //模拟兔子休息
            if (Thread.currentThread().getName().equals("兔子")&& i%10==0){
                try {
                    Thread.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //判断比赛是否结束
            boolean flag = gamcOver(i);
            //如果比赛结束了就停止程序
            if (flag){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
        }
    }

    //判断是否完成比赛
    private boolean gamcOver(int steps) {
        //判断是否有胜利者
        if (Winner != null) {  //已经存在胜利者
            return true;
        }
        {
            if (steps >= 100) {
                Winner = Thread.currentThread().getName();
                System.out.println("winner is" + Winner);
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        Race race = new Race();

        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }
}



//给兔子加延迟  使胜利者必须是乌龟

扩展了解:实现Callable接口

实现Callable接口 徐涛返回值类型

重写call方法 需要抛出异常

import Dem01.TestThread02;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

//线程创建方式三:实现Callable接口
/*
 Callable的好处
 1.可以定义返回值
 2.可以抛出异常
 */
public class TestCallable implements Callable<Boolean> {

    private String url;//网络图片地址
    private String name;//保存的文件名

    public TestCallable(String url,String name){
        this.url = url;
        this.name = name;
    }
    //下载图片线程的执行体
    @Override
    public Boolean call() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
        return true;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable t1 = new TestCallable("https://p5.ssl.qhimgs1.com/dmfd/128_96_80/t0119191d9915b1b3f5.webp","2.jpg");
        TestCallable t2 = new TestCallable("https://p5.ssl.qhimgs1.com/dmfd/128_96_80/t0119191d9915b1b3f5.webp","2.jpg");
        TestCallable t3 = new TestCallable("https://p5.ssl.qhimgs1.com/dmfd/128_96_80/t0119191d9915b1b3f5.webp","2.jpg");

        //创建执行服务
        ExecutorService  ser = Executors.newFixedThreadPool(3);

        //提交执行
        Future<Boolean> r1 = ser.submit(t1);
        Future<Boolean> r2 = ser.submit(t1);
        Future<Boolean> r3 = ser.submit(t1);

        //获取结果
        boolean rs1 = r1.get();
        boolean rs2 = r2.get();
        boolean rs3 = r3.get();

        System.out.println(rs1);
        System.out.println(rs2);
        System.out.println(rs3);

        //关闭服务
        ser.shutdownNow();
    }
}
//下载器
class WebDownloader{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出现问题");
        }
    }
}

静态代理模式

import org.omg.PortableServer.THREAD_POLICY_ID;

//静态代理模式总结
//真实对象和代理对象都要实现同一个接口
//代理对象要代理真实角色
//好处:
   //代理对象可以做很多真实对象做不了的事情
   //真实对象专注做自己的事情
public class StacticProxy {
    public static void main(String[] args) {
        You you = new You();//你要结婚
        new Thread(()-> System.out.println("我爱你")).start();

        WeddingCompany weddingCompany = new WeddingCompany(new You());
        weddingCompany.HappyMarry();
    }
}
interface Marry{
    void HappyMarry();
}
//真实角色
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("秦老师要结婚了,超开心");
    }
}
//代理角色
class WeddingCompany implements Marry{
    //代理谁-->真实目标角色
    private Marry target;

    public WeddingCompany(Marry target){
        this.target = target;
    }

    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();//这就是真实对象
        after();
    }

    private void after() {
        System.out.println("结婚之后,收尾款");
    }

    private void before() {
        System.out.println("结婚之前 布置现场");
    }
}

Lambda表达式

package Lamda;

public class TestLambda2 {

   static class Love implements Ilove{//静态内部类
        @Override
        public void love(int A) {
            System.out.println("i Love you01-->"+A);
        }
    }
    public static void main(String[] args) {

        class Love implements Ilove{//局部内部类
            @Override
            public void love(int A) {
                System.out.println("i Love you02-->"+A);
            }
        }
        //1.Lambda表达式简化
        Ilove love = (int A)-> { //由匿名内部类 推导成为的Lambda表达式
                System.out.println("i Love you04-->"+A);
        };
        //简化1.去掉参数类型
        love = (A)->{
            System.out.println("i Love you05-->"+A);
        };
        love.love(8);

        //简化2.简化括号
        Ilove finalLove = love;
        love = A -> {
            System.out.println("i Love you06-->" + A);
        };
        love.love(88);

        //简化3.去掉花括号 { }   注:只能有一行代码
        love = A-> System.out.println("i Love you07-->" + A);
        //总结:
             //lambda表达式只能有一行代码的情况下才能简化成为一行,如果有多行就用代码块包裹
             //前提是接口必须是函数式接口
        //多个参数 也可以去掉参数类型,如果要去掉就全部去掉,必须加上括号
        love.love(888);
    }
}
interface Ilove{
    void love(int A);
}

Lambda的作用

  • 避免匿名内部类定义过多
  • 可以让代码看起来更简洁
  • 去掉没有意义的代码,只留核心逻辑
停止线程

线程的五大状态

  • 创建状态,就绪状态,运行状态,阻塞状态,死亡状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OijLeJsr-1628778428801)(C:\Users\Administrator.USER-20190630SI\Desktop\线程的五大状态.jpg)]

package state;
//测试stop
//1.建议线程正常停止-->利用次数,不建议死循环
//2.设置一个标志位-->设置标志位
//3.不要使用stop或者destroy等过时或者JDK不建议使用的方法
public class TestStop implements Runnable{
    //1.设置一个标志位
   private boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while (flag){
            System.out.println("run...Thread"+i++);
        }
    }
    //2.设置一个公开的方法停止线程,转换标志位
    public void stop(){
        this.flag = false;
    }
    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        new Thread(testStop).start();

        for (int i = 0; i <= 10; i++) {
            System.out.println("main"+i);
            
            if (i == 3){
                //调用stop方法切换标志位,让线程停止
                testStop.stop();
                System.out.println("线程该停止了");
            }
        }
    }
}
线程休眠 sleep

模拟倒计时

//模拟倒计时
public class TestSleep2 {

    public static void main(String[] args) {
        try {
            tenDown();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
    //模拟倒计时
    public static void tenDown() throws InterruptedException {
        int num = 10;
        while (true) {
            Thread.sleep(1000);
            System.out.println(num--);
            if (num<=0){
                break;
            }
        }
    }
}
  • sleep(时间)制定法当前线程阻塞的毫秒数
  • sleep 存在异常 InterruptedException
  • sleep 时间达到后线程进入就绪状态
  • sleep 可以模拟网络延时,倒计时等
import java.text.SimpleDateFormat;
import java.util.Date;

//打印和更新系统当前时间
public class TestSleep2 {

    public static void main(String[] args) {
        //打印当前系统时间
        Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间
        while (true) {
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("hh:mm:ss").format(startTime));
                startTime = new Date(System.currentTimeMillis());//更新当前时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
线程礼让 yield
  • 礼让线程,让当前正在执行的线程暂停,但不阻塞
  • 讲线程先从运行状态转为就绪状态
  • 让CPU重新调度,礼让不一定成功,看CPU心情

例:有A,B两条线程,礼让成功就是AB AB 失败就是AA BB

//测试礼让线程
//礼让不一定成功,主要看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()+"线程停止执行");
    }
}
线程强制执行 join

待此线程执行完成后,在执行其他线程,其他线程阻塞

//测试join方法   可以当做是插队
public class TestJoin implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 4; 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 < 10; i++) {
            if(i==6){
                thread.join();//插队
            }
            System.out.println("main"+i);
        }
    }
}

线程状态观测

线程状态,线程可以处于以下状态之一

  • NEW—尚未启动的线程处于此状态
  • RUNNABLE—在Java虚拟机中执行的线程处于此状态
  • BLOCKED—被阻塞等待监视器锁定的线程处于此状态
  • WAITING—正在等待另一个线程执行特定动作的线程处于此状态
  • TIMED_WAITING----正在等待另一个线程执行动作达到指定等待时间的线程处于此现状
  • TERMINATED----已退出的线程处于此状态
//观察测试线程的状态
public class TestState {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try{
                    Thread.sleep(1000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println("");
        });
        //观察状态
        Thread.State state = thread.getState();
        System.out.println(state);//NEW

        //观察启动后
        thread.start();//启动线程
        state = thread.getState();
        System.out.println(state);//Run

        while (state != Thread.State.TERMINATED){//只要线程不终止就有一直输出状态
            Thread.sleep(100);
            state = thread.getState();//更新线程状态
            System.out.println(state);//输出状态
        }
    }
}

线程的优先级 Priority

优先级低只是意味着获取得调度的概率低,并不是优先级低的就不会被调用了,这都是看CPU的调度

//测试线程的默认优先级
public class TestPriority {

    public static void main(String[] args){
        //主线程的默认优先级
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());

        MyPriority myPriority = new MyPriority();

        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        Thread t5 = new Thread(myPriority);

        //先设置优先级,再启动
        t1.start();

        t2.setPriority(1);
        t2.start();

        t3.setPriority(4);
        t3.start();

        t4.setPriority(Thread.MAX_PRIORITY);MAX_PRIORITY = 10
        t4.start();

        t5.setPriority(8);
        t5.start();
    }
}
class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
}

守护线程Daemon
public class TestDaemon {
    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 < 3; i++) {
            System.out.println("你一生都开心的活着");

        }
        System.out.println("-====godbye! world!=======");
    }
}
三大不安全线程案例
//不安全的买票
//线程不安全,存在负数
public class UnsafeBuyTicket {

    public static void main(String[] args) {
        BuyTicket station = new BuyTicket();

        new Thread(station,"灰太狼").start();
        new Thread(station,"黑猫警长").start();
        new Thread(station,"葫芦娃他爷爷").start();
    }
}
class BuyTicket implements Runnable{
    //票
    private int ticketNums = 10;
    boolean flag = true;//停止外部方式
    @Override
    public void run() {
        //买票
        while (flag){
            try {
                buy();
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    private void buy() throws InterruptedException {
        //判断是否邮票
        if (ticketNums<=0){
            return;
        }
        //模拟延时
        Thread.sleep(100);
        //买票
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }
}
//不安全的取钱
//两个人去银行 取钱
public class UnsafeBank {
    public static void main(String[] args) {
        //z账户
        Account account = new Account(100,"结婚基金");
        Drawing you = new Drawing(account,50,"你");
        Drawing girlFriend = new Drawing(account,100,"妻子");

        you.start();
        girlFriend.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() {
        //判断有没有钱
        if (account.money-drawingMoney<0){
            System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
            return;
        }
        //模拟延时
        //sleep 可以放大问题的发生性
        try {
            Thread.sleep(1000);
        } 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);
    }
}
//线程不安全的集合
public class UnsafeList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i <= 10000; i++) {
            new Thread(() -> {
                list.add(Thread.currentThread().getName());
            }).start();
        }
        System.out.println(list.size());
    }
}

同步方法及同步块

同步方法

//不安全的买票
//线程不安全,存在负数
//使用锁synchronized 解决
public class UnsafeBuyTicket {

    public static void main(String[] args) {
        BuyTicket station = new BuyTicket();

        new Thread(station,"灰太狼").start();
        new Thread(station,"黑猫警长").start();
        new Thread(station,"葫芦娃他爷爷").start();
    }
}
class BuyTicket implements Runnable{
    //票
    private int ticketNums = 10;
    boolean flag = true;//停止外部方式
    @Override
    public void run() {
        //买票
        while (flag){
            try {
                buy();
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    //synchronized 同步方法,锁住的是this
    private synchronized void buy() throws InterruptedException {
        
        //判断是否邮票
        if (ticketNums<=0){
            return;
        }
        //模拟延时
        Thread.sleep(100);
        //买票
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }
}

同步代码块

//不安全的取钱
//两个人去银行 取钱
//使用锁 synchronized
public class UnsafeBank {
    public static void main(String[] args) {
        //z账户
        Account account = new Account(100,"结婚基金");
        Drawing you = new Drawing(account,50,"你");
        Drawing girlFriend = new Drawing(account,100,"妻子");

        you.start();
        girlFriend.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;
    }
    //取钱
    //synchronized  默认锁的是this 也就是他本身
    @Override
    public void run() {
        //锁的对象就是变化的量,需要 增 删 改
        synchronized(account){//锁块  synchronized

            //判断有没有钱
            if (account.money-drawingMoney<0){
                System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
                return;
            }
            //模拟延时
            //sleep 可以放大问题的发生性
            try {
                Thread.sleep(1000);
            } 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);
        }
    }
}

扩充:JUC安全类型的集合

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 < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

死锁

产生死锁的四个必要条件:

  • 互斥条件:一个资源每次只能被一个人进程使用
  • 请求与保持条件:一个进程请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
  • 新欢等待条件:若干进程之间形成一种头尾相连的循环等待资源关系。

解决方法:只要想办法破以上其中任意一个或多个条件就可以避免死锁发生

//死锁:多个线程互相抱着对方需要的资源 形成僵持
public class DeadLock {
    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 girlNmae;//使用化妆品的人

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

    @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.girlNmae + "获得口红的锁");
                Thread.sleep(1000);

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

                synchronized (lipstick) {//一秒钟后想获得口红的锁
                    System.out.println(this.girlNmae + "获得口红的锁");
                }
            }
        }
    }
}

解决死锁问题

避免在程序运行的时候 程序相互同时持有对方所需要的锁

//死锁:多个线程互相抱着对方需要的资源 形成僵持
public class DeadLock {
    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 girlNmae;//使用化妆品的人

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

    @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.girlNmae + "获得口红的锁");
                Thread.sleep(1000);
            }
            synchronized (mirror) {//一秒钟后想获得镜子的锁
                System.out.println(this.girlNmae + "获得镜子的锁");
            }
        } else {
            synchronized (mirror) {//获得镜子的锁
                System.out.println(this.girlNmae + "获得镜子的锁");
                Thread.sleep(2000);
            }
            synchronized (lipstick) {//一秒钟后想获得口红的锁
                System.out.println(this.girlNmae + "获得口红的锁");
            }
        }
    }
}

Lock锁

import java.util.concurrent.locks.ReentrantLock;

//测试lock锁
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 tickerNums = 10;
    //定义lock锁
    private final ReentrantLock lock = new ReentrantLock();

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

生产者与消费者模型

管程方式解决

//测试:生产者消费之模型-->利用缓冲区解决:管程法
//生产者,消费者,产品,缓冲区
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++) {
            System.out.println("生产了"+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++) {
            System.out.println("消费了-->"+container.pop().id+"只鸡");
        }
    }
}
//产品=鸡
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 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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值