java - 线程
1、什么是进程?什么是线程?
进程是一个应用程序
线程是一个进程中的执行场景/执行单元
一个进程可以启动多个线程。
2、对于java程序来说,当在DOS命令窗口中输入
java HelloWorld回车之后
会先启动JVM而JVM就是一个进程
同时启动多个线程。
3、理解:进程A和进程B的内存独立不共享。
线程A和线程B呢?
在java中:
线程A和线程B,堆内存和方法区内存共享
但是在栈区独立,一个线程一个栈
java中启动10个线程就有10个栈,每个栈和每一个栈之间互不干扰。这就是多线程并发
java中之所以有多线程机制,目的就是问了提高程序的处理效率
4、思考问题:
使用了多线程机制之后,main方法结束,是不是有可能程序也不会结束。
main方法结束只是主线程结束了,主栈空了,其它的栈(线程)可能还在弹栈压栈。
5、对于多核的cpu电脑来说,真正的多线程并发是没问题的
对于单核的cpu电脑:
不能做到真正的多线程开发,但是可以做到给人一种错觉,多个线程之间频繁的切换,给人一种并发的错觉
6、实现线程的第一种方式:
编写一个类,直接继承java.long.Thread,重写run方法
怎么创建线程对象,直接new
怎么启动线程呢?调用对象的start()方法
7、实现类的第二种方式:
编写一个类区实现java.lang.Runnable接口,实现run方法
//定义一个可运行的类
public class MyRunnable implements Runnable{
public void run (){
}
}
//创建线程对象
Thread t = new Thread(new MyRunnable());
//启动线程
t.start();
8、关于线程对象的生命周期?
新建状态
就绪状态
运行状态
阻塞状态
死亡状态
9、获取线程对象的名字:
String name = 线程对象.getName();
10、修改线程的名字:
线程对象.setName();
11、怎么获取当前线程对象?
Thread t = Thread.currentThread();
返回值t就是当前线程。
12、关于线程的sleep方法
static void sleep(Long millis)
静态方法:Thread.sleep(1000);
参数是毫秒
作用:让当前线程进入休眠,进入“阻塞状态”,放弃占有cpu时间片,让给其他线程使用。
可以做到,间隔特定的时间,去执行一段特定的代码。
13、唤醒睡眠:
void interrupt()
中断这个线程。
14、合理的终止线程
在一个类中做一个boolean标记。
15、常见的线程调度模型有哪些?
抢占式调度模型:
那个线程的优先级比较高,抢到的cpu时间片就多
java采用的就是抢占式调度模型
均分式调度模型:
平均分配cpu时间片,每一个线程占有的时间片一样
平均分配,一切平等
16、java中提供了那些方法是和线程调度有关系的呢?
实列方法:
int getPriority()
返回此线程的优先级。
void setPriority(int newPriority)
更改此线程的优先级。
静态方法:
static void yield()
暂停当前正在执行的线程对象,并执行其他线程。
yield()方法不是阻塞方法,让当前线程让位,让给其他线程
yield()方法的执行会让当前线程从“运行状态”回到“就绪状态”
注意:回到就绪状态之后,有可能还会再次抢到时间片。
实例方法:
void join()
等待这个线程死亡。合并线程
17、多线程并发环境下,数据安全问题:
什么时候在多线程并发的环境下会存在安全问题
条件一:多线程并发
条件二:共享数据
条件三:共享数据有修改的行为
满足以上三个条件之后,就会存在线程安全问题
18、怎么解决线程安全问题
线程排队执行(不能并发)。
用排队执行解决线程安全问题
这种机制叫做:线程同步机制
19、异步编程模型:
线程1和线程2,各自执行各自的,互不干扰,谁也不需要等谁,效率高
其实就是:多线程并发
20、同步编程模型:
线程1和线程2存在等待关系,线程1执行的时候,线程2等待,反之亦然
同步编程模型就是:排队等待,效率较低
21、如何实现线程安全
synchronized(){}实现线程安全。
22、java中的三大变量:
实例变量 堆中
静态变量 方法区中
局部变量 栈中
以上三种变量中:
局部变量永远不会发生存在线程安全问题
因为局部变量不共享(一个线程一个栈)
实例变量在堆中,静态变量在方法区中。
堆和方法区都是多线程共享的,所以可能存在线程安全问题
23、在实例方法上可以使用synchronized吗?可以
synchronized出现在实例方法上,锁的是this
synchronized还会无故扩大同步范围,效率低
24、总结:
synchronized有三种写法:
第一种:同步代码块
灵活
synchronized(线程共享对象){
同步代码块;
}
第二种:在实例方法上使用synchronizde
表示共享对象一定是this
同步代码块是整个方法体
第三种:在静态方法上使用synchronizde
表示找类锁
类锁只有一把
25、死锁现象:
死锁的产生原因: 对并发资源的加锁成“环”
26、在开发中应该怎么解决线程安全问题?
第一步:尽量使用局部变量代替实例变量和静态变量
第二部:如果必须是实例变量,那么可以考虑采用创建多个对象的方式。
第三步:如果不能使用局部变量,对象也不能创建多个,这个时候就只能选择synchronized了。线程同步机制。
27、守护线程
方法:
void setDaemon(boolean on)
将此线程标记为 daemon线程或用户线程。
java语言中线程分为两大类
用户线程
守护线程
其中具有代表性的是:垃圾回收线程(守护线程)
守护线程的特点:
一般守护线程就是一个死循环,所有的用户线程之要结束,守护线程也会结束
注意:主线程main方法是一个用户线程
28、定时器
定时器的作用:间隔特定的时间,执行特定的程序
在实际的开发中,每隔多久执行一段特定的程序,这种需求是很常见的。
在java中其实可以采用多种方式实现
可以使用sleep方法,睡眠,设置睡眠时间,这种是最原始的定时器。
在java类库中已经写好了一个定时器,java.util.Timer下的,可以直接拿来使用。
在实际的开发中,目前使用较多的是Sping框架的SpingTask框架
这个框架只要进行简单的配置,就可以完成定时器设置。
29、实现线程的第三种方式:FutureTask方式。实现:Callable接口
实现Callable接口
这种方式的优点:可以获取到线程的执行结果
这种方式的缺点:在获取t线程的执行结果的时候,当前线程受阻塞,效率较低。
30、关于Object类中的wait和notify方法(生产者和消费者模式)
第一;wait和notify方法不是线程对象的方法,是java对象上都有的方法
因为这两个方法是Object类中自带的。
wait方法和notify方法不是通过线程对象调用。
第二:wait()方法作用?
Object o = new Object();
o.wait();
表示:
让正在o对象上活动的线程进入等待状态,无限制等待直到唤醒为止,并且释放t线程之前占用o对象的锁。
第三:notify()方法的作用:
Object o = new Object();
o.notify();
表示:
唤醒正在o对象上等待的线程
还有一个notifyAll()方法
这个方法是唤醒o对象上处于等待的所有线程。不会释放锁。