一、线程和进程的区别
进程是操作系统分配资源的最小单元;线程是CPU的最小执行单元,也是进程中的一个顺序执行流程。 一个程序至少有一个进程,一个进程至少有一个线程。
二、并发和并行
并发:同一时间段上,同时执行,可以单核CPU来完成。 并行:同一时间点上,同时执行,必须多核CPU才能完成。
三、线程的创建方式
1、实现Runnable接口,重写run方法
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"----"+i);
}
}
}
public class TestRunnable {
public static void main(String[] args) {
//创建MyRunnable对象,表示线程要执行的功能
MyRunnable runnable = new MyRunnable();
//创建线程
Thread thread = new Thread(runnable, "我的线程1");
//启动线程
thread.start();
for (int i = 0; i < 50; i++) {
System.out.println("main--------" + i);
}
}
}
2、继承Thread类,重写run方法
public class MyThreadDemo1 extends Thread{
@Override
public void run() {
}
public static void main(String[] args) {
MyThreadDemo1 myThreadDemo1 = new MyThreadDemo1();
Thread thread = new Thread(myThreadDemo1);
thread.start();
}
}
3、实现Callable接口,重写call方法
public class MyThreadCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return 1+1;
}
public static void main(String[] args) {
MyThreadCallable myThreadCallable = new MyThreadCallable();
//把callable对象转成可执行任务
FutureTask<Integer> task = new FutureTask<>(myThreadCallable);
Thread thread = new Thread(task);
thread.start();
try {
System.out.println(task.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
四、线程的安全问题
- 原子性问题:当一个线程执行一系列程序指令操作的时候,它应该是不可中断的,一旦中断,在多线程的视角来看,这一系列的程序指令会出现前后执行结果不一致的问题。
- 可见性问题:多线程环境下,由于读和写是发生在不同的线程里面,有可能出现某个线程共享变量的修改,对其他线程不是实时可见的。
- 有序性问题:程序编写的指令顺序和最终CPU运行的指令顺序可能出现不一致的现象,这种现象称为指令重排序,有序性也会导致可见性问题。
五、线程的生命周期
- new:初始化状态
- runnable:运行状态
- waiting:阻塞状态(无限期等待)
- timed_waiting:阻塞状态(限期等待)
- blocked:阻塞状态,只有在遇到synchronized锁的时候,且没有抢占到锁,线程才会进入该状态。
- terminated:终止状态
六、start()方法和run()方法的区别
只有调用了start()方法,才会启动线程,才会表现出多线程的特性,不同线程的run()方法里面的代码交替执行,如果只是调用了run()方法,那么代码还是同步执行,必须等待一个线程的run()方法里面的代码全部执行完毕之后,另外一个线程才可以执行其run()方法里面的代码。
七、Runnable接口和Callable接口的区别
Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹的去执行run()方法中的逻辑代码而已。 Callable接口中的call()方法是有返回值的,是一个泛型,Future、FutureTask配合可以用来获取异步执行的结果。
八、sleep()方法和wait()方法区别
sleep()方法
- 属于Thread类中的方法,
- 不释放对象锁
- 可以设置等待时间,监控状态依然保持着,当指定时间到了会自动恢复运行状态。
wait()方法
- 属于Object类中的方法
- 会释放对象锁
- 不会设置等待时间,只有针对此对象调用notify()方法后本线程才会重新获取对象锁进入运行状态,或者notifyAll()方法唤醒全部wait的线程。
九、sleep()方法和yield()方法有什么区别
- sleep()方法给其他线程运行机会时,不考虑线程的优先级,都是抢占式的;yield()方法只会给相同优先级或者更高优先级的线程以运行的机会。
- 线程执行sleep()方法后转入阻塞状态;执行yield()方法会转入就绪状态。
- sleep()方法声明抛出InterruptedException异常;yield()方法没有声明任何异常。
- sleep()方法比yield()方法具有更好的可移植性。
十、notify()和notifyAll()有什么区别
- notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。
- notify()唤醒一个正在等待该对象的线程;notifyAll()唤醒所有正在等待该对象的线程。
- notify()可能导致死锁;notifyAll()不会导致死锁。
- notifyAll()可以唤醒所有处于wait状态的线程,使其重新进入锁的竞争队列中;notify()只能唤醒一个。
总结
等等。我还有一句话要说,生活已经很累了,但是要记得爱自己。