首页 > 代码库 > java进阶07 线程的让步与阻塞与同步

java进阶07 线程的让步与阻塞与同步

  前面介绍了线程的一些基本知识,现在来说下线程的让步,阻塞,和同步

  先说说让步

  所谓让步,就是让调用者的线程暂停,让其他线程重新竞争CPU,包括调用者。

  先看看代码

  

package Thread;

public class ThreadYield {
    public static void main(String[] args){
        MyThread5 rthread=new MyThread5();
        
        Thread thread1=new Thread(rthread);
        Thread thread2=new Thread(rthread);
        
        thread1.setName("线程1");
        thread2.setName("线程2");    
        
        thread1.start();    
        thread2.start();
        
        
    }
}
//通过实现接口Runnable实现
class MyThread5 implements Runnable{

    public void run(){
        
            for(int i=1;i<=30;i++){                
                System.out.println(Thread.currentThread().getName()+"正在执行"+i);
                if(i%5==0){
                Thread.yield();//线程的让步   将该线程暂停 然后重新让所有线程争取CPU
                System.out.println("重新竞争CPU");
                }
        }            
    }
}

  我们来分析下该代码

  代码中的Thread.yield()就是让步的函数,这里循环30次 当i为5的倍数的时候 让步 同时打出 重新竞争CPU的字段

  那我们期待的结果就是这样的形式:

  线程1正在执行1
  线程1正在执行2
  线程1正在执行3
  线程1正在执行4
  线程1正在执行5
  重新竞争CPU
  线程1正在执行6
  线程1正在执行7
  线程1正在执行8
  线程1正在执行9
  线程1正在执行10
  重新竞争CPU

  那我们来看看真正打出结果:

  线程2正在执行1
  线程1正在执行1
  线程2正在执行2
  线程1正在执行2
  线程2正在执行3
  线程2正在执行4
  线程2正在执行5
  重新竞争CPU
  线程2正在执行6
  线程2正在执行7
  线程1正在执行3
  线程2正在执行8
  线程1正在执行4
  线程2正在执行9
  线程1正在执行5
  重新竞争CPU

  这可跟我们期待的值差太多了。

  这是什么原因呢? 还是由于CPU的分配的问题,CPU分配是随机的,什么时候当前线程被其他线程抢去也不奇怪。

  还有可能出现这种结果:

  线程1正在执行5
  线程2正在执行5
  重新竞争CPU
  重新竞争CPU

  这就是当程序i=5的倍数时,运行完System.out.println(Thread.currentThread().getName()+"正在执行"+i);

  该线程就被挤出去了,导致 for里面都只运行了一半.

  而为了处理这种情况,提供了一种叫同步的东西:

  所谓线程同步,就是在一段程序执行的过程中,无论成功还是失败,其他线程都会等待这段程序的执行完毕,才会转入其他线程

  这样可以保证程序的完整性和安全性。
  java里用synchronsized关键值实现

  它既可以修饰代码块,又可以修饰函数。

  

package Thread;

public class ThreadSynchronized {
    public static void main(String[] args){
        
            MyThread7 rthread=new MyThread7();
            
            Thread thread1=new Thread(rthread);
            Thread thread2=new Thread(rthread);
            
            thread1.setName("线程1");
            thread2.setName("线程2");    
            
            thread1.start();    
            thread2.start();
                    
    }
}

//通过实现接口Runnable实现
class MyThread7 implements Runnable{
    String word=new String("Word");
    public void run(){
        synchronized (word) {
            for(int i=1;i<=30;i++){                
                System.out.println(Thread.currentThread().getName()+"正在执行"+i);
                if(i%5==0){
                Thread.yield();//线程的让步   将该线程暂停 然后重新让所有线程争取CPU
                System.out.println("重新竞争CPU");
                }
        }            
        }        
    }
}

  输出结果:

  线程1正在执行1
  线程1正在执行2
  线程1正在执行3
  线程1正在执行4
  线程1正在执行5
  重新竞争CPU
  线程1正在执行6
  线程1正在执行7
  线程1正在执行8
  线程1正在执行9
  线程1正在执行10
  重新竞争CPU

  这就达到了我们想要的结果。

  最后讲到的就是线程的阻塞。

  调用Thread.join()会 阻塞当前线程,直至调用者的线程执行完毕之后,才执行其他线程,相当于将CPU全部分给调用者的线程。从而达到控制线程的先后顺序

  

package Thread;

public class ThreadJion {
    public static void main(String[] args){
        MyThread6 rthread=new MyThread6();
        Thread thread=new Thread(rthread);
        thread.setName("线程1");
        thread.start();
        
        
        
        try {
            thread.join();//阻塞当前线程 直到调用方全部执行完
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("线程阻塞出错");
        }
        for(int i=0;i<500;i++)
            System.out.println("主线程正在执行");
    }
}
//通过实现接口Runnable实现
class MyThread6 implements Runnable{

    public void run(){
            
            for(int i=0;i<10000;i++){                
                System.out.println(Thread.currentThread().getName()+"正在执行"+i);                            
        }            
    }
}

  输出结果:

  线程1正在执行9998
  线程1正在执行9999
  主线程正在执行
  主线程正在执行

 

  可以看出新开的线程和主线程不会出现互相交替出现的时候了,因为新开线程阻塞了主线程,只有等到该线程全部执行完毕的时候,才会执行主线程

  关于线程的东西就先说到这里了。