Java面向对象程序设计第9章1-9

Java面向对象程序设计第9章1-9

1. 线程和进程的联系和区别是什么?

联系:

  1. 一个进程可以包括多个线程。

区别:

进程: 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是系统进行资源分配和调度的一个独立单位

线程: 线程是进程的一个实体,是CPU调度和分配的基本单位。线程基本不拥有系统资源,与同一个进程的其他线程共享进程中所拥有的所有资源。


2. 什么是前台线程,什么是后台线程?

应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束


3. 创建线程有几种方法?它们之间的区别是什么?

第一种方式直接继承线程Thread类创建对象
1.Thread子类无法再从其它类继承(java语言单继承)。
2.编写简单,run()方法的当前对象就是线程对象,可直接操作。

public MyThread extends Thread{
     …… 
     public void run() {  线程体逻辑 }   
}
//创建及启动线程:
MyThread t = new MyThread();
t.start(); 
    

第二种方式:使用Runnable接口创建线程
1.可以实现多个线程资源共享
2.线程体run()方法所在的类可以从其它类中继承一些有用的属性和方法

public MyThread implements Runnable {
             …… 
             public void run() {  线程体逻辑 }    
        }
//创建及启动线程:
MyThread t = new MyThread();
Thread t1 = new Thread(t);
t1.start(); 

4.线程的生命周期有哪些状态?哪些方法可以改变这些状态?

1572082134052

  1. 创建状态:线程对象已经创建,还没有在其上调用start()方法。
  2. 可运行状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到可运行状态。
  3. 运行状态:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。
  4. 阻塞状态:这是线程有资格运行时它所处的状态。如执行了join/sleep/wait方法,会让出CPU,只有当引起阻塞的原因消除时,线程才能转入就绪状态。
  5. 死亡态:当线程的run()方法完成时就认为它死去。或者抛出一个未捕获到的Exception或Error。

5.什么是线程安全?为什么会产生线程安全问题?如何解决线程安全问题?

线程安全:线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
原因是由于不同线程获取到资源时进行运算,但未来得及写入时,线程改变,则另外线程读入的资源就是错误,导致所有线程写入读入不同步。
解决办法:

使用监视器,使用关键字synchronized监视同步代码块,当一个线程获得监视权限时,别的线程就无法获得,保证每时每刻只有一个线程调用某一方法

6.什么是线程的同步通信?同步通信又是如何实现的?

线程同步通信是希望实现两个或多个线程之间的某种制约关系
实现:首先是用监视器synchronized来保证每次只有一个线程调用方法,其次引入一个boolean型标志来判断该线程是否执行或wait,两个线程时使用notify(),多个线程时用notifyAll()来让出监视器并唤醒其他线程。这样就实现了线程之间的关系。

//使用wait和notifyAll实现线程间同步通信 (两个存钱线程,一个取钱线程)
class Account{
    volatile private int value;
    //布尔标志              
    volatile private boolean isMoney = false;   
    
    //put设为同步方法
    synchronized void put(int i) {
      while(isMoney){
        try{ wait();} //线程等待
        catch(){Exception e}{} 
      }
      value = value + i; 
      System.out.println("存入"+i+" 账上金额为:"+value);
      isMoney = true;//设置标志
      notifyAll(); //唤醒等待资源的所有线程
   }
   synchronized int get(int i) {//同步方法 
    while(!isMoney) ){
        try { wait();}
        catch(){Exception e}{}
     }
     if (value>i)
          value = value - i;         
     else {  
          i = value;
          value = 0;                    
     }
     System.out.println("取走"+i+" 账上金额为:"+value);
     isMoney = false;
     notifyAll(); 
     return i;                      
    } 
}

class  Save implements Runnable{
  private Account a1;     
  public Save(Account a1){this.a1 = a1;}
  public void run(){
      while(true){ a1.put(100);}
  }
}

class Fetch implements Runnable {
  private Account a1;
  public Fetch(Account a1) { this.a1 = a1 ;}
  public void run(){       
       while(true){ a1.get(100);}
  }
}

public class TestCommunicate{
 public static void main(String[] args){
    Account a1 = new Account();
    new Thread(new Save(a1)).start(); new Thread(new Save(a1)).start();      
    new Thread(new Fetch(a1)).start();
 }}

7.什么是死锁?

如果多个线程都处于等待状态,彼此需要对方所占用的监视器所有权,

就构成死锁(deadlock),Java即不能发现死锁也不能避免死锁。

方法一:{
synchronized(A) {
     ….
    synchronized(B) {
        ….
    }
}
}

方法二:{
synchronized(B) {
     ….
    synchronized(A) {
        ….
    }
}
}

注意

  1. 可能发生死锁的代码执行中不一定会死锁,因为线程之间的执行存

    在很大的随机性。

  2. 线程方法suspend()、resume()、stop()由于存在引起死锁的可能,

    因而逐渐不用(Deprecated)。


8.如何让某个对象的A方法内的一个代码块和另一个方法B实现同步?

class Account                              
{
    volatile private int value;
    void put(int i)                       
    {
        synchronized(this) {
        value = value + i; 
        System.out.println("存入"+i+" 账上金额为:"+value);
        }
    }
    synchronized int get(int i)                         
    {   
        if (value>i)
                value = value - i;             
            else                               
            {   i = value;
                value = 0;                     
            }
        System.out.println("取走"+i+" 账上金额为:"+value);
      return i;                      
    }    
}
class  Save implements Runnable            
{
    int a=2000;
    private Account a1;     
    public Save(Account a1)
    {
        this.a1 = a1;
    }
    public void run()
    {
        while(a-->0){
            a1.put(100);            
        }
    }
}
class Fetch implements Runnable            
{
    int a=2000;
    private Account a1;
    public Fetch(Account a1)
    {this.a1 = a1 ;}
    public void run()
    {       
        while(a-->0){       
            a1.get(100);            
        }       
    }
}
public class Test{
    public static void main(String[] args){
       Account a1 = new Account();
       new Thread(new Save(a1)).start(); 
       new Thread(new Fetch(a1)).start();
    }
}

put方法的代码块被监视,get函数被监视,保证了value的正确性,输出结果为存钱取钱的随机顺序, 这里没有设置存取的制约关系。


9.设计一个程序产生两个线程A与B,B线程执行10秒钟后,被A线程中止。

public class test {//如何中断线程?答案是添加一个开关。
    private volatile static boolean on = false;

    //内部类
    public class MyThreadTwo implements Runnable {
        @Override
        public void run() {
            try {
                System.out.println("into ---" + Thread.currentThread().getName());
                Thread.sleep(10000);//由于等待时间10秒,输出多,上面的into语句被覆盖了
                System.out.println("out " + Thread.currentThread().getName());
                test.on=true;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void start() {
        //一个Thread的构造函数接受一个Runnable参数,而传入的lambda表达式正好符合其run()函数,
        // 所以Java编译器推断它为Runnable。
        Thread thread1 = new Thread(() -> {
            while (!on) {
                System.out.println(Thread.currentThread().getName());
            }
        });
        Thread thread2 = new Thread(new MyThreadTwo());

        thread1.start();
        thread2.start();
    }

    public static void main(String[] args) {
        test test = new test();
        test.start();
    }
}

10.补充(选做):编写一个基于多线程的生产者/消费者程序,各产生10个生产者和消费者线程,共享一个缓冲区队列(长度自设),生产者线程将产品放入到缓冲区,消费者线程从缓冲区取出产品。

class Cache {
    volatile private int value;
    final private int productSize;

    public Cache(int pro) {
        productSize = pro;
    }

    synchronized void put() {//存
        while (value == productSize) {//缓存区产品长度满时等待,不存
            try {
                wait();//线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        value = value + 1;
        System.out.println(Thread.currentThread().getName() + "存了" + 1+", 现value=" + value);
        notifyAll();//唤醒等待资源的所有线程
    }

    synchronized void get() {//取
        while (value == 0) {//缓存区产品长度空时等待,不取
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        value = value - 1;
        System.out.println(Thread.currentThread().getName() + "取了" + 1+", 现value=" + value);
        notifyAll();
    }
}

//生产者
class produce implements Runnable {
    private Cache a1;

    public produce(Cache a1) {
        this.a1 = a1;
    }

    public void run() {
        while (true) {
            a1.put();
        }
    }
}

//消费者
class consumer implements Runnable {
    private Cache a1;

    public consumer(Cache a1) {
        this.a1 = a1;
    }

    public void run() {
        while (true) {
            a1.get();
        }
    }
}

public class test{
    public static void main(String[] args) {
        Cache a1=new Cache(20);
        //10个生产者
        new Thread(new produce(a1)).start();
        new Thread(new produce(a1)).start();
        new Thread(new produce(a1)).start();
        new Thread(new produce(a1)).start();
        new Thread(new produce(a1)).start();
        new Thread(new produce(a1)).start();
        new Thread(new produce(a1)).start();
        new Thread(new produce(a1)).start();
        new Thread(new produce(a1)).start();
        new Thread(new produce(a1)).start();

        //10个消费者
        new Thread(new consumer(a1)).start();
        new Thread(new consumer(a1)).start();
        new Thread(new consumer(a1)).start();
        new Thread(new consumer(a1)).start();
        new Thread(new consumer(a1)).start();
        new Thread(new consumer(a1)).start();
        new Thread(new consumer(a1)).start();
        new Thread(new consumer(a1)).start();
        new Thread(new consumer(a1)).start();
        new Thread(new consumer(a1)).start();
    }
}

在这里开始对volatile不是很了解其机制,记得老师讲了i--的操作三条指令,详细了解了下,具体看:

面试官最爱的volatile关键字

猜你喜欢

转载自www.cnblogs.com/He-Fan/p/11766965.html