1 . 线程与进程区别
进程:具有一定独立的功能的程序关于某个数据集合上的一次运行活动,是操作系统进行资源分配和调度的一个独立单位
线程:是进程的的一个实体,是cpu调度和分派的基本单位,是比进程更小的可以独立运行的基本单位
特点:线程的划分尺度小于进程,这使多线程程序拥有高并发性
2 . 启动线程是用run方法还是star方法
启动线程用star()方法,使线程所代表的虚拟处理机处于可运行状态,它由JVM调度并执行,这不意味着线程会立即执行
run()方法是线程启动后要进行回调(callback)的方法
start()方法开启线程,无需等待run方法体代码执行完毕而直接执行下面的代码.
run()方法是线程体,包含了要执行的这个线程的内容,run()方法运行结束,此线程随即终止.
如果直接调用run方法,程序中依然只有主线程这一个线程
3 . 编写多线程的几种实现方式
- 通过继承Thread类
- 通过实现Runable接口(推荐使用,因为Thread是一个类,java中继承是单继承,一个类只有一个父类,无法继承其他类,而接口则不一样,接口更为灵活)
- 通过实现callable接口
4 . 解决多线程安全的几种方式
1 . 同步代码块
在代码块声明上,加上synchronize
synchronize(锁对象){
可能会才产生线程安全的代码
}
(ps: 同步代码块中锁对象可以是任意对象,但是多个线程时,要使用同一个锁对象才能保证线程安全)
2 . 同步方法
在方法声明上加上synchronize
public synchronize void method(){
可能会产生线程安全的代码
}
3 . 同步锁
lock接口,不过需要手动获取锁和释放锁
5 . synchronized与lock与voltatile区别
synchronized是java的关键字,在jvm层面上,lock是一个类
synchronized,假如A获得线程,B线程一直等待.lock获取锁,线程可以不用一直等待
synchronized无法判断锁的状态, lock可以判断.而且lock是可重入,公平的.
volatile只能使用在变量级别,synchronized可以使用在变量, 类, 方法上.
一个线程修改volatile修饰的共享变量,其它线程可以立即可见.synchronized修饰的变量,
只能在当前线程访问,其它线程阻塞.
volatile不会造成线程的阻塞.synchronized可能会造成线程的阻塞.
6 . sleep()和wait()的区别
**sleep:**sleep()方法是Thread类的方法,线程通过调用该方法,进入休眠状态主动让出CPU,从而CPU可以执行其他的线程。经过sleep指定的时间后,CPU回到这个线程上继续往下执行。
如何当前线程进入了同步锁,sleep()方法并不会释放锁。即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行。
如果线程在休眠时被打断,JVM就会抛出InterruptedException异常。
因此,必须在try-catch语句块中调用sleep方法。
wait:wait()方法可以中断线程的运行,使本线程等待,暂时让出CPU的使用权,并允许其他线程使用这个同步方法。其他线程如果在使用这个同步方法时不需要等待,那么它使用完这个方法的同时,应该用notifyAll()方法通知所有由于使用了这个同步方法而处于等待的线程结束等待,曾中断的线程就会从刚才中断处继续执行这个同步方法(并不是立马执行,而是结束等待),并遵循“先中断先继续”的原则。
wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。如果notify方法后面的代码还有很多,需要这些代码执行完后才会释放锁,可以在notfiy方法后增加一个等待和一些代码,看看效果)
wait()、notify()和notifyAll()都是Object类的final方法,被所有的类继承且不允许重写的方法。
特别需要注意的是,不可以在非同步方法中使用上述三个方法。(从功能和使用场合也可以看出)
package thread;
public class MultiThread {
public static void main(String[] args) throws InterruptedException {
new Thread(new Thread1()).start();
Thread.sleep(5000);//主动让出CPU,让CPU去执行其他的线程。在sleep指定的时间后,CPU回到这个线程上继续往下执行
new Thread(new Thread2()).start();
}
}
class Thread1 implements Runnable{
@Override
public void run() {
synchronized (MultiThread.class){
System.out.println("进入线程1");
try{
System.out.println("线程1正在等待");
Thread.sleep(5000);
// MultiThread.class.wait();//wait是指一个已经进入同步锁的线程内(此处指Thread1),让自己暂时让出同步锁,
//以便其他在等待此锁的线程(此处指Thread2)可以得到同步锁并运行。
}catch(Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}
System.out.println("线程1结束等待,继续执行");
System.out.println("线程1执行结束");
}
}
}
class Thread2 implements Runnable{
@Override
public void run() {
synchronized (MultiThread.class){
System.out.println("进入线程2");
System.out.println("线程2唤醒其他线程");
MultiThread.class.notify();//Thread2调用了notify()方法,但该方法不会释放对象锁,只是告诉调用wait方法的线程可以去
//参与获得锁的竞争了。但不会马上得到锁,因为锁还在别人手里,别人还没有释放。如果notify()
//后面的代码还有很多,需要执行完这些代码才会释放锁。
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2继续执行");
System.out.println("线程2执行结束");
}
}
}
7 . 线程对的五种状态
新建状态、就绪状态、运行状态、阻塞状态、死亡状态
阻塞状态:
①调用sleep方法进入睡眠状态
②线程调用一个I/O上被阻塞的操作,
③线程师徒得到一个锁,而该锁正被其他线程持有
④线程等待某个触发条件
所谓阻塞状态,是正在运行的线程没有结束,但是咱是让出cpu,从而让其他线程获得cpu时间,得到运行
死亡状态:
①线程正常退出而死亡
②一个未捕获的异常终止了run方法使得线程猝死
8 . 什么是进程死锁
两个进程都在等待对方执行结束才开始执行,这就造成了进程死锁,两个进程都进入了无限的等待过程