13. Java 中多线程间的通信怎么实现?
线程通信的方式:
1.共享变量
线程间通信可以通过发送信号,发送信号的一个简单方式是在共享对象的变量里设置信号值。线程 A 在一个同步块里设置 boolean 型成员变量 hasDataToProcess 为 true,线程 B 也在同步块里读取 hasDataToProcess这个成员变量。这个简单的例子使用了一个持有信号的对象,并提供了 set 和 get 方法:
1.package itheima.com;
2.public class MySignal{
3. //共享的变量
4. private boolean hasDataToProcess=false;
5. //取值
6. public boolean getHasDataToProcess() {
7. return hasDataToProcess;
8. } 9. //存值
10. public void setHasDataToProcess(boolean hasDataToProcess) {
11. this.hasDataToProcess = hasDataToProcess;
12. }
13. public static void main(String[] args){
14. //同一个对象
15. final MySignal my=new MySignal();
16. //线程 1 设置 hasDataToProcess 值为 true
17. final Thread t1=new Thread(new Runnable(){
18. public void run() {
19. my.setHasDataToProcess(true);
20. }
21. });
22. t1.start();
23. //线程 2 取这个值 hasDataToProcess
24. Thread t2=new Thread(new Runnable(){
25. public void run() {
26. try {
27. //等待线程 1 完成然后取值
28. t1.join();
29. } catch (InterruptedException e) {
30. e.printStackTrace();
31. }
32. my.getHasDataToProcess();
33. System.out.println("t1 改变以后的值:" + my.isHasDataToProcess());
34. }
35. });
36. t2.start();
37.}
38.}
结果:
t1 改变以后的值:true
2.wait/notify 机制
以资源为例,生产者生产一个资源,通知消费者就消费掉一个资源,生产者继续生产资源,消费者消费资源,以
此循环。代码如下:
1.package itheima.com;
2.//资源类
3. class Resource{
4. private String name;
5. private int count=1;
6. private boolean flag=false;
7. public synchronized void set(String name){
8. //生产资源
9. while(flag) {
10. try{
11. //线程等待。消费者消费资源
12. wait();
13. }catch(Exception e){}
14. }
15. this.name=name+"---"+count++;
16. System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
17. flag=true;
18. //唤醒等待中的消费者
19. this.notifyAll();
20. }
21. public synchronized void out(){
22. //消费资源
23. while(!flag) {
24. //线程等待,生产者生产资源
25. try{wait();}catch(Exception e){}
26. }
27. System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
28. flag=false;
29. //唤醒生产者,生产资源
30. this.notifyAll();
31. }
32.}
33. //生产者
34. class Producer implements Runnable{
35. private Resource res;
36. Producer(Resource res){
37. this.res=res;
38. }
39. //生产者生产资源
40. public void run(){
41. while(true){
42. res.set("商品");
43. }
44. }
45. }
46. //消费者消费资源
47. class Consumer implements Runnable{
48. private Resource res;
49. Consumer(Resource res){
50. this.res=res;
51. }
52. public void run(){
53. while(true){
54. res.out();
55. }
56. }
57. }
58.public class ProducerConsumerDemo{
59. public static void main(String[] args){
60. Resource r=new Resource();
61. Producer pro=new Producer(r);
62. Consumer con=new Consumer(r);
63. Thread t1=new Thread(pro);
64. Thread t2=new Thread(con);
65. t1.start();
66. t2.start();
67. }
68.}
14. 线程和进程的区别
进程:具有一定独立功能的程序关于某个数据集合上的一次运行活动,是操作系统进行资源分配和调度的一个独
立单位。
线程:是进程的一个实体,是 cpu 调度和分派的基本单位,是比进程更小的可以独立运行的基本单位。
特点:线程的划分尺度小于进程,这使多线程程序拥有高并发性,进程在运行时各自内存单元相互独立,线程之间内存共享,这使多线程编程可以拥有更好的性能和用户体验
注意:多线程编程对于其它程序是不友好的,占据大量 cpu 资源。
15. 请说出同步线程及线程调度相关的方法?
wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理 InterruptedException 异常;
notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由 JVM 确定唤醒哪个线程,而且与优先级无关;
notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;
注意:java 5 通过 Lock 接口提供了显示的锁机制,Lock 接口中定义了加锁(lock()方法)和解锁(unLock()方法),增强了多线程编程的灵活性及对线程的协调
16. 启动一个线程是调用 run()方法还是 start()方法?
启动一个线程是调用 start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由 JVM 调度并执行,这并不意味着线程就会立即运行。
run()方法是线程启动后要进行回调(callback)的方法。
十、Java 内部类
17. 静态嵌套类 (Static Nested Class) 和内部类(Inner Class)的不同?
静态嵌套类:Static Nested Class 是被声明为静态(static)的内部类,它可以不依赖于外部类实例被实例化。
内部类:需要在外部类实例化后才能实例化,其语法看起来挺诡异的。
18. 下面的代码哪些地方会产生编译错误?
1.class Outer {
2.3.class Inner {}
4.5.public static void foo() { new Inner(); }
6.7.public void bar() { new Inner(); }
8.9.public static void main(String[] args) {
10.new Inner();
11.}
12.}
注意:Java 中非静态内部类对象的创建要依赖其外部类对象,上面的面试题中 foo 和 main 方法都是静态方法,静态方法中没有 this,也就是说没有所谓的外部类对象,因此无法创建内部类对象,如果要在静态方法中创建内
部类对象,可以这样做
1.new Outer().new Inner();