天天看点

Java-多线程总结(面试题)

传统使用类Thread和接口Runnable实现

  1. 在Thread子类覆盖的run方法中编写运行代码
new Thread(){ 
 @Override  
 public void run(){  
  while(true){    
  try {  
     Thread.sleep(2000);   
      } catch (InterruptedException e) {  
         e.printStackTrace(); 
   } 
  } 
   } }.start(); 
           
  1. 在传递给Thread对象的Runnable对象的run方法中编写代码
new Thread(new Runnable(){  
public void run(){  
 while(true){   
  try {   
    Thread.sleep(2000);  
      } catch (InterruptedException e) { 
          e.printStackTrace();   
           } 
   System.out.println(Thread.currentThread().getName());   
   } 
    }    
   }).start(); 
           
  1. 总结

查看Thread类的run()方法的源代码,可以看到其实这两种方式都是在调用Thread对象的run方法,如果Thread类的 run 方法没有被覆盖,并且为该 Thread 对象设置了一个 Runnable 对象,该 run 方法会调用 Runnable 对象的run方法.

请模拟写出双重定时器(面试题)

class TimerTastCus extends TimerTask {
        @Override
        public void run() {
            count = (count + 1) % 2;
            System.err.println("Boob boom ");
            new Timer().schedule(new TimerTastCus(), 2000 + 2000 * count);
        }
    }

    Timer timer = new Timer(); timer.schedule(new

    TimerTastCus(), 2000+2000*count); 
 
while(true)

    {
        System.out.println(new Date().getSeconds());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {   // TODO Auto-generated catch block   e.printStackTrace();  } } 
//PS:下面的代码中的 count 变量中 
// 此参数要使用在你匿名内部类中,使用 final 修饰就无法对其值进行修改, 
// 只能改为静态变量 private   static volatile int count  = 0; 
        }

           

多线程的创建方式

  • (1)继承Thread类:但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的 start()实例方法.start()方法是一个native方法,它将启动一个心线程,并执行run()方法. 这种方式实现多线程很简单,通过自己的类直接 exthed Thread, 并复写run()方法,就可以启动新线程并执行自己定义的run()方法.例如:继承Thread类实现多线程,并且在合适的地方启动线程.
  • (2)实现Runnable接口的方式实现多线程,并且实例化Thread,传入自己的Thread实例,调用run( )方法
  • (3)使用ExecutorService、Callable、Future实现有返回结果的多线程:ExecutorService、Callable、Future这 个 对 象 实际 上 都是属 于 Executor 框 架中 的 功 能 类。 想 要详细 了 解 Executor 框架 的 可 以 访问http://www.javaeye.com/topic/366591 ,这里面对该框架做了很详细的解释。返回结果的线程是在JDK1.5中引入的新特征,确实很实用,有了这种特征我就不需要再为了得到返回值而大费周折了,而且即便实现了也可能漏洞百出。可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。执行Callable任务后,可以获取一个 Future 的对象,在该对象上调用 get 就可以获取到 Callable 任务返回的 Object 了,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了。下面提供了一个完整的有返回结果的多线程测试例子,在JDK1.5下验证过没问题可以直接使用.

在 java 中 wait 和 sleep 方法的不同?

  • 最大的不同是在等待时wait会释放锁,而sleep一直持有锁。wait通常被用于线程间交互,sleep通常被用于暂停执行。

synchronized 和 volatile 关键字的作用

  • 一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
  • 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
  • 2)禁止进行指令重排序。

    volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;

    synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。

    1.volatile仅能使用在变量级别;

    synchronized则可以使用在变量、方法、和类级别的

    2.volatile仅能实现变量的修改可见性,并不能保证原子性;

    synchronized则可以保证变量的修改可见性和原子性

    3.volatile不会造成线程的阻塞;

    synchronized可能会造成线程的阻塞。

    4.volatile标记的变量不会被编译器优化;

    synchronized标记的变量可以被编译器优化