线程的创建
创建线程有三种方式 thread,runnable,callable。
- 继承Thread类
public class Test1 extends Thread{
public static void main(String[] args) {
Test1 test = new Test1();
test.start();
}
@Override
public void run(){
//do something
}
}
- 实现Runnable接口
public class Test2 implements Runnable {
public static void main(String[] args) {
Thread t1 = new Thread(new Test2());
t1.start();
}
@Override
public void run() {
//do something
}
}
- 实现Callable接口
public class Test3 implements Callable<Integer> {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> task = new FutureTask<Integer>(new Test3());
new Thread(task).start();
Integer result = task.get();
System.out.println(result);
}
@Override
public Integer call() throws Exception {
//dosomething
return 0;
}
}
Callable是泛型接口,泛型中的类型正是调用call返回的类型。
为什么使用Runnable而不是Thread
答:
- 使用类继承Thread 不适合资源共享,
- 避免Java中单继承的限制
- 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
Runnable和Callable的区别
答: Callable接口支持返回执行结果,Runnable不行。Callable接口的call()可以抛出异常V call() throws Exception;
Runnable的run()只能内部捕获处理。
run() 和 start()的区别
答:由代码可以看到,run方法只是调用了target的run方法,还是在主线程中运行并未开启新的线程。而start()调用后,启动了新的线程。
public
class Thread implements Runnable {
/* What will be run. */
private Runnable target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
线程的中断
Thread# void interrupt 向线程发送中断请求,将中断flag置为true
Thread# static boolean interrputed 测试线程是否为中断状态,重置中断flag为false
Thread# isInterrputed 测试线程是否为中断状态,不会重置中断flag
正确的使用interrupt终止线程的姿势
public void run() {
while(!Thread.currentThread().isInterrupted()){
System.out.println("...");
Thread.currentThread().interrupt();
}
}
wait()和notify()/notifyAll()
wait和notify/notifyAll都是Object类的方法
一个线程调用了object.wait( )后,这个线程就会进入该共享资源的等待队列,释放共享资源的锁。
调用了object.notify( )后,会随机唤醒该资源的等待队列中随机一个线程(唤醒后线程并不能立即进入可运行状态(Runnable),而是进入阻塞状态(Blocked)等待获得锁)
image.png image.png
wait 和notify/notifyAll都需要在synchronized语句中才能执行。
注意:IllegalMonitorStateException
synchronized锁住的对象应该和调用wait与notify一样。
/**
* wait 和 notify/notifyAll的demo
* 生产者消费者模型
* Created by tjc on 2018-10-16.
*/
public class Test5 {
int count = 0;
public static void main(String[] args) {
Test5 test5 = new Test5();
new Thread(new Product(test5)).start();
new Thread(new Customer(test5)).start();
}
}
class Product implements Runnable {
Test5 test5 = null;
Product(Test5 test5){
this.test5 = test5;
}
@Override
public void run() {
synchronized (test5) {
while (true) {
while (test5.count >= 5) {
try {
test5.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
test5.count++;
if(test5.count>=5) test5.notifyAll();
System.out.println(test5.count);
}
}
}
}
class Customer implements Runnable {
Test5 test5 = null;
Customer(Test5 test5){
this.test5 = test5;
}
@Override
public void run() {
synchronized (test5) {
while (true) {
while (test5.count <= 0) {
try {
test5.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
test5.count--;
if(test5.count<=0) test5.notifyAll();
System.out.println(test5.count);
}
}
}
}
注意:wait通常和while一起使用
wait和sleep的区别
答:wait 会释放锁,sleep不会
yield() 和 join()
yield让优先级更高的线程执行
join让调用线程先执行
网友评论