多线程基础
并行与并发
-
并发是指一个处理器同时处理多个任务。
-
并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。
打个比方:在并发的状态下,餐厅里只有一个厨师,尽管他做事利索,餐厅的客人等待每道菜的时间都不会太久。没有客人觉得上菜慢,但对于厨师,在某个时间点上,他只能炒某一桌客人的菜。并行则是多个厨师同时处理客人的订单。
线程与进程
现代操作系统都支持多任务并发执行:你可以在打开音乐播放器听歌的同时打开word进行编辑。这种情况我们称为进程级的并发,如果是在一个线程中同时执行多个任务,则称这些任务为线程。(操作系统可以通过上下文切换的方式实现并发)
创建线程
继承Thread类,实现run方法
public class Thread0 extends Thread {
@Override
public void run() {
System.out.println("extends thread");
}
public static void main(String[] args) {
Thread thread0=new Thread0();
thread0.start();
}
}
实现Runnable接口,实现run方法
实际上Thread类就是一个Runnable接口的实现类。
“黑纸白字”写的清清楚楚
public class Thread1 implements Runnable {
@Override
public void run() {
System.out.println("implements Runnable");
}
public static void main(String[] args) {
//两种皆可
new Thread(new Thread1()).start();
//
Thread1 thread1=new Thread1();
Thread thread=new Thread(thread1);
thread.start();
}
}
虽然我们通过继承Thread类来创建线程,但并不推荐这种做法。因为Java是不支持多继承的,你这个类继承了Thread就无法再继承别的类了,这可能给以后的修改带来麻烦。相比之下,使用Runnable接口要灵活的多。
需要注意的是,同一个线程只能调用一次start方法,如果直接调用run方法会变成串行执行。
比较违反直觉的是,main线程可能早于子线程结束。感兴趣可以自己验证一下,实际上在多线程种违反直觉的并不止这一个,之后的博文会讲到,这也是人们头疼之所在。
守护线程
守护线程是一种特殊的线程,听起来跟天使奶妈差不多的。你的感觉是对的,一个经典的守护线程就是Java的垃圾回收器。
总的来说:当同一个应用程序中没有其他线程运行时,守护线程才运行(它的优先级往往很低)。当其是程序中唯一运行的线程时,程序会在它结束之后终止。
sleep和wait的区别
最主要的区别就是虽然两者都会让出CPU但sleep不会释放锁,wait会释放锁。
其他的区别有
- sleep来自Thread类,wait来自Object类
- sleep需要捕获异常
- wait只能在synchronized方法或者synchronized块中使用
工厂类创建线程
使用工厂类可以将对象的创建集中化,更易于控制。
-
更容易修改类
-
方便限制创建对象的数目
-
方便对创建的对象进行统计
这里仅给出简单的实现
public class MyThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable runnable) {
Thread t=new Thread(runnable);
return t;
}
public static void main(String[] args) {
MyThreadFactory factory=new MyThreadFactory();
Thread1 thread1=new Thread1();
System.out.println("the thread start");
Thread thread;
for(int i=0;i<10;i++){
thread=factory.newThread(thread1);
thread.start();
}
}
}
参考:
- https://www.cnblogs.com/plmnko/archive/2010/10/15/1851854.html
- http://concurrent.redspider.group/article/01/1.html