线程同步的两个方法

Thread的yield()方法:

	yield方法是让出当前线程的cpu时间,所有的线程公平竞争

例如:


public class ThreadDemo01 {
    public static void main(String[] args) {
        YieldTest yt1=new YieldTest();
        yt1.setName("十堰");
        YieldTest yt2=new YieldTest();
        yt2.setName("苍穹");

        yt1.start();
        yt2.start();

    }
}
class YieldTest extends Thread{
    @Override
    public void run(){
        for (int i = 1; i < 100; i++) {
            System.out.println(getName()+"------"+i);
            if (i%10==0){
                yield();//当i取余10等于0的时候,让出当前线程的cpu时间片
            }
        }
    }

}

Thread的join():

用于等待指定线程结束之后才可以执行该线程

例如:图片的缓存和显示


public class ThreadDemo02 {

    //定义一个开关,用于表示线程是否正常下载
    public static boolean isFinish=false;
    public static void main(String[] args) {


        //图片下载线程
        Thread download=new Thread(){
            @Override
            public void run() {
                System.out.println("download:开始下载");
                for (int i=0;i<=100;i++){
                    System.out.println("download:已下载"+i+"%");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("download:图片下载完成----");
                isFinish=true;//用于表示线程执行下载结束,表示正常下载

            }

        };
        //图片显示线程
        Thread show=new Thread(){
            @Override
            public void run() {
                try {
                    //System.out.println("show:图片要显示了----");
                    System.out.println("show:正在等在下载----");
                    //规定当下载线程执行完之后,开采可以执行当前线程
                    //要等待下载线程结束
                    download.join();//表示download线程执行完之后,才可以执行当前线程
                    //判断是否发生异常
                    if (isFinish){
                        System.out.println("图片显示完成");
                    }else{
                        System.out.println("图片没有下载完成,请稍等");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        download.start();
        show.start();
    }
}

在这里插入图片描述
线程的同步异步:

  1. 线程同步:多个线程访问同一个资源,其他线程等待当前线程访问资源结束(加锁,线程安全),浪费时间,效率不高
  2. 线程异步:访问资源的时候,如果有空闲时间,则可以在等待的时间访问资源,实现多线程

如下车票的同步


public class ThreadDemo03 {
    public static void main(String[] args) {
        TicketDemo tt=new TicketDemo();
        Thread t1=new Thread(tt,"火车站窗口");
        Thread t2=new Thread(tt,"美团售票窗口");
        Thread t3=new Thread(tt,"自动售票窗口");
        Thread t4=new Thread(tt,"携程售票窗口");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        /*
        四个窗口卖票,出现重票(:数重复) 错票(:少数)
        为什么会出现这个问题?
        三个窗口都在操作车票,当火车站在卖票的时候,卖票的操作没有结束;美团参与进来了
            就会出现线程安全问题,
        出现问题如何解决
            线程同步;
            当一个线程进入车票操作的时候,其他线程不允许参与进来,直到当前线程操作结束,才允许其他线程进入
         */

    }
}
class TicketDemo implements Runnable{
    int ticket=5;
    @Override
    public void run() {
        //同步代码块,上锁
//        while (true){
//            //当第一个线程票数1,判断票数大于0?还没有对票数进行操作时
//            //第二个线程又开始了,票数还是1,判断票数大于0的
//            synchronized (this){
//                //操作共享数据的代码
//                if (ticket>0){
//                    System.out.println(Thread.currentThread().getName()+"----:"+ticket);
//                    ticket--;
//                }else{
//                    break;
//                }
//            }
//        }

        while (true){
            if (show()){
            }else{
                break;
            }
        }
    }
    public synchronized boolean show(){
        if (ticket>0){
            System.out.println(Thread.currentThread().getName()+"---------"+ticket);
            ticket--;
        }else {
            return false;
        }
        return true;
    }
}

在这里插入图片描述
java如何解决线程安全问题

  1. 同步代码块(上锁)
  2. 同步方法

同步代码块:

 synchronize(同步监视器){
     //需要被同步的代码块,
  }
 同步监视器:任何一个类的对象都可以来充当,俗称锁(多线程必须公用一把锁)
 需要被同步的代码块:操作共享数据的代码

同步方法:

将方法声明为同步的,将操作共享数据的代码放入这个方法即可

在上述的车票同步为题:这两个方法都使用了,只是方法一被注释了,使用的是方法二

同步资源的死锁:

  • 不同的线程分别占用几个对象需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

注意:出现死锁之后,不会出现异常,也不会出现提示,只是所有的线程都处于阻塞状态无法继续工作,所以我们在使用同步资源的时候,避免出现死锁线程

避免死锁:

  1. 尽量避免同步的嵌套
  2. 尽量减少同步资源的定义 (同步资源没了,就不会出现死锁)
  3. 专门的算法/原则

一个简单死锁代码:


public class ThreadDemo04 {
    public static void main(String[] args) {
        StringBuffer sb1=new StringBuffer();
        StringBuffer sb2=new StringBuffer();
        /*
        Thread t=new Thread(){
            public void run(){
            }

        };
        t.start();
         */
        //简写如下:

        //死锁

        //第一个线程中,先锁sb1,往sb1后追加1,往sb2后追加a
            //再锁sb2,往sb1后追加2,往sb2后追加b
        new Thread(){
            @Override
            public void run() {
                synchronized (sb1){
                    sb1.append("1");
                    sb2.append("a");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (sb2){
                        sb1.append("2");
                        sb2.append("b");
                        //输出
                        System.out.println(getName()+"---"+sb1);
                        System.out.println(getName()+"---"+sb2);
                    }
                }
            }
        }.start();
        //第二个线程,先锁sb2,往sb1后追加3,往sb2后追加c
                //再锁sb1,往sb1后追加2,往sb2后追加b
        new Thread(){
            @Override
            public void run() {
                synchronized (sb2){
                    sb1.append("3");
                    sb2.append("c");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (sb1){
                        sb1.append("4");
                        sb2.append("d");
                        //输出
                        System.out.println(getName()+"---"+sb1);
                        System.out.println(getName()+"---"+sb2);

                    }
                }
            }
        }.start();
    }
}

今天的分享到此结束了,希望诸位能在此有个不少的收获,如果有错误的,麻烦斧正下,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值