并发,指的是多道程序交替执行,单核并发可以让用户感觉到是多个程序同时执行。而多核则可以真正实现进程的同时运行。
线程
线程的目的是为了执行某个任务,每条线程都认为自己独占CPU和内存。
创建线程
创建线程有三种方式 继承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 API
public static native Thread currentThread()
public final void join() throws InterruptedException
public static native void yield()
public static native void sleep(long millis) throws InterruptedException
public void interrupt()
public boolean isInterrupted()
public static boolean interrupted()
Object API
public final void wait() throws InterruptedException
public final native void notifyAll()
public final native void notify()
线程的中断
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)等待获得锁)


wait 和notify/notifyAll都需要在synchronized语句中才能执行。
注意:IllegalMonitorStateException
synchronized锁住的对象应该和调用wait与notify一样。
注意:wait通常和while一起使用
wait和sleep的区别
答:wait 会释放锁,sleep不会
/**
* 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);
}
}
}
}
yield() 和 join()
yield让优先级更高的线程执行
join让调用线程先执行
生命周期

