1、进程和线程的概念:
2、进程与线程之间的区别与联系
线程与线程之间共享堆内存和方法区内存,但是不共享栈内存,每个栈与每个栈之间,互不干扰,各自执行各自的,这就是多线程并发。
3、线程与栈的关系内存图
4、其实单核的cpu一个时间点只是执行一个线程,但是由于多个线程之间频繁快速切换,所以导致了给人类的感觉是多个线程都在被执行的过程中:
5、线程的创建方法一、
线程的两种创建方式:
首先要先定义一个线程类MyThread,然后通过线程类对象调用start函数来创建一个独立的线程,这个start()函数会自动调用run()函数。这个run()函数是自己重写的,里面放的是想要进行的操作。
6、直接调用run()方法和用start()方法间接调用run()方法的内存图区别
直接调用run()方法
调用run方法间接调用run()方法
7、在两个进程的执行过程中不一定打印是严格交替的,也可能是有先有后有多有少:
8、线程创建方法2、
通过实现一个Runnable接口,然后创建一个对象,对这个对象进行启动就可以创建一个线程了。
9、采用匿名内部类的方式创建线程对象
10、线程的生命周期(面试会问的)
11、获取线程对象
Thread是父类,这里直接调用父类的方法进行调出现在的线程。
12、线程的sleep方法
让当前进程进入阻塞状态,这个可以用来让程序延迟一段时间执行,这也可以作为每隔多久执行一次的时间计数器。sleep()不管调用的对象是哪个对象,它出现在哪个方法体中就让当前的线程进入休眠。
13、关于Thread.sleep()方法的一个面试题。
记住一点的是sleep()方法不管是谁调用它,都会导致它被转换成Thread.sleep()方法,也就是说在哪个方法体里面调用这个方法,对应的线程就会进入休眠
14、如何叫醒一个正在睡眠的线程
通过线程对象.interrupt()的方式,中断睡眠,通过给线程类中的Thread.sleep()加一个try........catch来捕捉异常。得以中断睡眠。
14、java中如何强行终止一个线程
使用线程对象.stop()方式(不建议,现在java已经弃用了);执行后线程被杀掉了,这种方式容易丢失数据。
15、怎样合理的终止一个线程的执行
这里主要用到的方法是:定义一个类体中加入布尔类型标记run,并判断这个标记是否为true,是的话再执行,不是就直接中断,然后将这个可执行的类体放入到主类中,决定线程是否要被终止
16、线程的调度(了解):
线程调度的几种方法
17、线程的优先级
使用setpriority()函数和gertpriority()函数来改变和获取线程的优先级,并调整线程的优先级,优先级高的得到的运行时间多一些,但不是优先级的高的就占用所有的运行时间。
18、调用静态方法Thread.yeild()来让当前线程暂停回到就绪状态,让给其他线程
19、通过join()方法进行线程合并
某个线程电泳join()方法,这个方法先执行,然后再执行本来应该执行的线程。
20、多线程并发环境下,数据安全问题
其实创建多线程,线程的启动,线程的修改等基本不会要求程序员去写,反而多线程的安全问题是写代码的过程中应该注意的问题。
首先想一个问题;
21、如何解决线程不安全问题,采用线程同步机制,让线程排队执行而不是并发执行。
22、同步编程模型和异步编程模型
23、编写程序模拟两个用户同时对一个账号进行取款,对比使用线程同步和不是用线程同步的区别
首先编写account账户类
编写一个线程类让两个用户共享同一个用户对象
编写一个测试程序
这里的测试结果会出现的是
出现了问题,两次取款5000,本来余额为10000,这时就出现了线程不安全
24、使用线程同步机制解决线程安全问题。
线程同步机制的语法是:
synchronized(线程同步代码块)
synchronized()后面小括号中传的这个数据相当关键。
这个数据必须是多线程共享的数据,才能达到多线程排队。
()中写什么?
那要看你想让哪些线程同步。
假设t1,t2,t3,t4,t5有五个线程。
你只希望t1,t2,t3,排队,t4 t5不需要排队。怎么办?
你一定要在()中写一个t1,t2,t3,共享的对象(必须是对象,不能是变量之类的)。而这个对象对t4,t5来说不共享。
创建一个银行账户引入线程同步机制,解决线程安全问题
注意这里面要共享的是银行账户,程序又是在银行账户中编写的,所以用this作为银行对象。
注意,因为字符串在常量池中,所有的对象都共享这个字符串,因此,写一个字符串所有的对象都要进行排队。
总结各变量是否有线程安全问题,成员变量是静态变量和实力变量,可能会出现线程安全问题,局部变量不会出现线程安全问题,因为局部变量在栈里,每个线程都有一个独立的栈,线程共享的是堆内存和方法区内存而不是栈的内存。
锁池不是一种状态,而是一种阻塞状态
25、在实例方法上可以用sychronized关键字吗?
26、多线程面试题
这个面试题的题目是doother方法执行的时候需要等待dosome方法结束吗?
答案是:不需要因为doother()方法不含有synchronized关键字,原因是当dosome执行时,吧this锁占住了,此时所有带sychronized的方法,都要在锁池里等待解锁,但是不带synchronized关键字的方法就不需要管这个,直接执行就可以了,总结起来就是,一个类中的所有的synchronized()需要排队执行,因为大家都需要this的锁,但是锁只有一把,所以要依次使用这把锁。
创建测试类
线程类
创建一个带有synchronized关键字方法的类,当实例方法上有synchronized关键字,那么表示锁this。
问题2:如果doother()方法含有synchronized关键字那么就需要等待了。
需要,大家都在抢this中的一把锁。
问题3:当测试类变成下面这种情况需要等待dosome方法结束吗?
不需要,因为两个对象两把锁,不存在资源共享的问题。
问题4:当测试类是问题3的测试类,但是类体有变化时如下图所示:
当类体变成下面这种情况需要等待dosome方法结束吗?
回答:需要:因为静态方法上的sychronized关键字所有的锁都是类锁,类锁不管创建多少个对象,都只有一把锁,因此,即使有两个对象也必须使用一把锁,因此需要排队执行才行。
27、死锁是什么
如下图,当t1和t2两个进程都要执行完两个带synchronized的方法体,才能结束时,当t1拿到第一个方法体要拿第二个方法体,而t2拿了第二个方法体要拿第一个方法体时,由于二者都没执行结束,因此,锁都没有释放,这就导致死锁的发生。
代码的实现,这个代码必须会写,因为面试的时候会问到:
死锁给我们一个启示,synchronized关键字不要嵌套使用,容易出现死锁的现象。
两个synchronized潜逃的方法体,导致了死锁线程的出现。
28、实际开发中应该遵循什么原则来保证线程安全呢?
29、线程还有那些内容
21、守护线程:
利用线程.setDaemon(true)函数,在线程运行之前将线程设置为守护线程,在主程序运行结束后守护线程自动结束。
22、定时器:
使用定时器指定定时任务
主要是用这个函数来进行定时任务的操作,这个函数在Timer类中。
这里的定时任务类是抽象类,不能创建对象,只能继承。
23、实现线程的第三种方式:实现Callable接口
创建未来任务类的方式是用匿名内部类的方式创建的。
24、生产者和消费者模式
wait方法和notify方法图解
生产者模式和消费者模式图解
编写代码实现生产者和消费者模式
25、作业: