传统使用类Thread和接口Runnable实现
- 在Thread子类覆盖的run方法中编写运行代码
new Thread(){
@Override
public void run(){
while(true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }.start();
- 在传递给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();
- 总结
查看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标记的变量可以被编译器优化