Java复习(一)

多线程线程同步有哪些方式?

答:首先说一下,多线程为什么要线程同步?当多个线程同时访问一个变量或对象,如果这些线程既有读操作又有写操作时,会造成变量值或对象的状态造成混乱,导致程序出现异常。如,银行存取钱问题,一个线程负责取钱100元,另一个线程负责存钱100元,当前账户余额为0元,取钱不成功,银行余额为100元,取钱成功了,余额为0元,到底是什么操作造成的,说不清楚,需要线程同步来解决。

(1)synchronized关键字

(2)volatile关键字

(3)可重入锁

(4)局部变量

(5)阻塞队列

(6)原子变量

使用了synchronized后还会不会发生死锁?

会,首先我们利用synchronized实现死锁:

public class Test {
    public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = new Object();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (o1){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                       e.printStackTrace();
                    }
                    synchronized (o2){
                    }
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (o2){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (o1){
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
}

排查死锁:

C:\Users\duanduan>jps

2656 Jps

13284 Launcher

7684 RemoteMavenServer

12408 Test

3208

C:\Users\duanduan>jstack 12408

Java stack information for the threads listed above:

===================================================

"Thread-1":

        at com.Test$2.run(Test.java:38)

        - waiting to lock <0x04b19798> (a java.lang.Object)

        - locked <0x04b197a0> (a java.lang.Object)

        at java.lang.Thread.run(Thread.java:748)

"Thread-0":

        at com.Test$1.run(Test.java:23)

        - waiting to lock <0x04b197a0> (a java.lang.Object)

        - locked <0x04b19798> (a java.lang.Object)

        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

从死锁发生的四个条件来分析:

(1)互斥条件:synchronized关键字保证只有一个线程可以操作,满足互斥条件

(2)请求与保持条件:利用synchronized实现死锁后,利用dump进行分析可以知道:两个线程各持有一个锁,且在互相尝试争夺对方的锁,而 两个线程都不愿意释放自己持有的锁;

(3)不可剥夺条件:synchronized没有执行完,锁不能释放;

(4)循环与等待条件:两个线程形成了明显的回路。

sleep与wait的区别?

答:

(1)是否释放锁:sleep()方法没有释放锁,wait()方法释放了锁

(2)方法属于类不同:sleep()方法是Thread类的静态方法,wait()方法是Object类的方法

(3)sleep()方法参数必须有时间参数,wait()方法可以有时间参数,可以没有时间参数

(4)sleep()方法线程调用,wait()方法必须与notify()/notifyAll()方法配合使用,且必须在synchronized中使用

一个线程调用sleep后,会不会有另一个线程运行?

答:不会,原因在于,线程调用了sleep()方法后,并未释放锁,其他线程无法获取锁,所以无法运行。

调用wait方法后呢?

答:会,原因在于,在调用某一个对象的wait()方法后,会释放锁,线程会暂停执行,将当前线程放入线程等待池中,当调用notify()/notifyAll()时,会将对象等待池中的任意一个线程/全部线程放入锁等待池,获取锁标志的线程可以争夺锁,获取锁资源后就可以运行。

如何理解线程池?

答:线程池中预先创建了一些工作线程,他们不断的从工作队列中取出任务,然后执行,当执行完之后,会继续执行工作队列中的下一个任务,减少了创建和销毁线程的次数,每个线程都可以一直被重用,避免了创建和销毁的开销。另外,可以根据系统的实际承载能力,方便的调节线程池中线程的数目,防止因为消耗过量的系统资源而导致系统崩溃的问题。

(1)提高相应速度,线程的创建与销毁需要时间,线程池的出现提升了响应速度;

(2)管理线程,将线程的创建与执行区分开,方便维护;

(3)避免大量的资源开销;

线程池节省了什么系统资源开销?

答: 首先,服务器创建和销毁工作线程的开销很大,如果服务器与很多客户端通信,并且与每个客户端通信的时间很短,那么就会在创建和销毁线程的时候造成很大的开销。

        其次,活动的线程也消耗系统资源,如果线程的创建数量没有限制,当大量的客户连接服务器的时候,就会创建出大量的工作线程,他们会消耗大量的内存空间,导致系统的内存空间不足,影响服务器的使用。

        最后,如果线程的数目固定,并且每个线程都有很长的生命周期,那么线程切换也就是固定的,这样就会给服务器减轻很多压力,但是如果频繁的创建和销毁线程,必将导致频繁的切换线程,使得线程之间的切换不再遵循系统的固定切换周期,线程切换的开销也会增大很多。

mysql的group by如何理解?

答:当group by 与聚合函数配合使用时,功能为分组后计算

当group by 与having配合使用时,功能为分组后过滤

当group by 与聚合函数,同时非聚合字段同时使用时,非聚合字段的取值是第一个匹配到的字段内容,即id小的条目对应的字段内容。

左右连接区别?

答:左连接:左表的记录会全部显示,右表只会显示符合搜索条件的记录,右表不足的地方均为NULL

       右连接:右表的记录会全部显示,左表只会显示符合搜索条件的记录,左表不足的地方均为NULL

       内连接:显示左右两表符合条件的搜索记录

linux系统的电脑使用了几年,内存要清理,如何清理?

清理缓存

(1)清理缓存前线sync(操作中的文件资料会被写入buffer中,操作前先将buffer中的资料写入硬盘)

(2)手动释放内存 echo 3 > /proc/sys/vm/drop_caches,其中

drop_caches的值可以是0-3之间的数字,代表不同的含义:0:不释放(系统默认值)1:释放页缓存,2:释放dentries和inodes,3:释放所有缓存

(3)free -h 查看内存是否已经释放掉

total——总物理内存

used——已使用内存,一般情况这个值会比较大,因为这个值包括了cache+应用程序使用的内存

free——完全未被使用的内存

shared——应用程序共享内存

buffers——缓存,主要用于目录方面,inode值等(ls大目录可看到这个值增加)

cached——缓存,用于已打开的文件

清理磁盘空间

(1) 执行   lsof | grep deleted发现有大量刚刚删除文件的进程存在,kill掉进程(或者重启进程) 

(2)用du命令查看各目录占用的空间,df -h命令查看磁盘信息

(3)文件恢复问题   https://blog.csdn.net/dutsoft/article/details/51248761

(4)快速定位超大文件目录并清理

      1)查看磁盘信息 df -h

      2)循环定位最大文件目录  du -h --max-depth=1  (找到一级目录,在cd切换到一级目录,再定位,,,)

      最大的文件如果在 ~/.local/share/Trash 下,而这个正是LInux下的垃圾箱(可以理解为windows回收站),平常想清理的话直接使用 sudo rm -rf ~/.local/share/Trash

3)定位最大文件ls -lhS

     4)确认删除的文件是否仍被占用/usr/sbin/lsof |grep deleted,根据第二列的pid,输入 kill -9 xxxx 杀掉进程xxxx

/dev/loop 100%的时候清理:命令:sudo apt autoremove --purge snapd

原文链接:https://blog.csdn.net/Gavinmiaoc/article/details/80527717

对于线程调度算法有哪些了解?

答:

(1)时间片轮转法:处理器的时间被分为最大长度不超过某个值的时间片段,然后轮转方法分配给每一个线程,当一个线程获得了处理器执行权后,按照自身逻辑执行直到时间片用完或自己主动放弃执行权,系统在获取处理器执行权后,会轮转寻找下一个线程,让他继续执行。

这种线程调度方法实现简单,所有满足运行条件的线程排成一个队列,然后按照时间片的间隔,轮流让每一个线程获得处理器执行权。由于时钟中断每次都要打断一个线程的运行,所以,这种做法存在固有的线程切换开销,而时间片长短的选择会影响到线程切换开销所占的比例。在现代操作系统中,时间片通常设置为几毫秒到几十、上百毫秒。由于现代计算机的指令周期越来越短,线程切换开销(通常几百条指令或几千条指令,取决于算法实现的复杂程度)也在减小。这种算法使用很广泛,它不仅简单,也确实能公平地分配处理器资源。

(2)先来先服务:所有的线程构成一个队列,最先进入队列的线程获得处理器执行权,等到放弃处理器执行权时,又回到队列尾部,下一个线程继续执行,当有新的线程会添加到队尾。

简单易实现,但如果每个线程需要执行的任务单元的执行时间长短不同的话,算法的实际效果可能很不公平;

(3)优先级调度算法 :时间片轮转法假设每个线程同等重要,实际上难以适用于不同应用程序并发执行的要求。基本思路: 每个线程都有一个优先级值,高优先级的线程总是优先被考虑在处理器上执行。操作系统在管理线程时,可以使用一个优先级队列,或者每一个优先级用一个队列来存放所有满足执行条件的线程,这样,当一个线程用完了它的时间片或者自动放弃处理器执行权时,系统选择优先级最高的线程作为下一个要运行的线程。每一个线程在队列中的位置是由它的优先级来决定的。同等优先级的线程使用轮转或先到先执行的策略。

高优先级的线程可能会霸占处理器资源不放,从而导致低优先级的线程一点执行机会都没有。所以,一些变种的优先级算法考虑引入动态优先级,即每个线程有静态的优先级和动态的优先级。所谓动态的优先级是在静态优先级的基础上根据某些特定的条件提升或降低线程的优先级,系统调度器根据线程的动态优先级来安排它们的执行顺序。例如,连续执行了多个时间片的线程可能要降低优先级,而长时间没有得到时间片的低优先级线程可能会得到优先级提升。

计算机网络对于端口的理解?

答:"端口"是英文port的意译,可以认为是设备与外界通讯交流的出口。端口可分为虚拟端口和物理端口,其中虚拟端口指 计算机内部 或 交换机 路由器内的端口,不可见。例如计算机中的80端口、21端口、23端口等。物理端口又称为接口,是可见端口,计算机背板的RJ45网口,交换机路由器集线器等RJ45端口都属于物理端口。

       在网络技术中,端口(Port)有好几种意思。集线器、路由器、交换机的端口指的是连接其他的。我们 这里所指的端口不是指物理意义上的端口,而是特指TCP/IP协议中的端口,是逻辑意义上的端口。

      如果把IP地址比作一间房子 ,端口就是出入这间房子的门。真正的房子只有几个门,但是一个IP地址的端口可以有65536(即:2^16)个之多!端口是通过端口号来标记的,端口号只有整数,范围是从0 到65535(2^16-1)。

       本地操作系统会给那些有需求的进程分配协议端口(protocol port,即我们常说的端口),每个协议端口由一个正整数标识(即端口号),如:80,139,445,等等。当目的主机接收到数据包后,将根据报文首部的目的端口号,把数据发送到相应端口,而与此端口相对应的那个进程将会领取数据并等待下一组数据的到来。

       端口其实就是队,操作系统为各个进程分配了不同的队,数据包按照目的端口被推入相应的队中,等待被进程取用,在极特殊的情况下,这个队也是有可能溢出的,不过操作系统允许各进程指定和调整自己的队的大小。

8080端口同80端口,是被用于WWW代理服务的,可以实现网页浏览,经常在访问某个网站或使用代理服务器的时候,会加上“:8080”端口号。

端口:21服务:FTP

端口:22服务:Ssh

端口:23服务:Telnet

端口:25服务:SMTP

端口:80服务:HTTP

GET请求与POST请求的区别:

1. get是从服务器上获取数据,post是向服务器传送数据。

2. GET请求把参数包含在URL中,将请求信息放在URL后面,POST请求通过request body传递参数,将请求信息放置在报文体中。

3. get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。

4. get安全性非常低,get设计成传输数据,一般都在地址栏里面可以看到,post安全性较高,post传递数据比较隐私,所以在地址栏看不到, 如果没有加密,他们安全级别都是一样的,随便一个监听器都可以把所有的数据监听到。

5. GET请求能够被缓存,GET请求会保存在浏览器的浏览记录中,以GET请求的URL能够保存为浏览器书签,post请求不具有这些功能。

6. HTTP的底层是TCP/IP,GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。你要给GET加上request body,给POST带上url参数,技术上是完全行的通的。

7.GET产生一个TCP数据包,对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);POST产生两个TCP数据包,对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据),并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

介绍一下volatile

volatile关键字主要用于修饰变量,有两个作用:(1)可见性(2)禁止指令重排序;但volatile不能保证原子性;

一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,就具备了两层含义:

1>保证了修饰的变量在线程之间具有“可见性”,即在一个线程对变量进行修改,能够在另外一个线程感知到变量被修改

2>禁止指令的重排序

禁止指令重排序有两层意思:1>当程序执行到volatile变量的读操作或者写操作的时候,在其前面的操作的更改肯定全部已经进行,且对后面的操作可见;2>在进行指令优化的时候,不能将在堆volatile变量访问的语句放在后面去执行,也不能把volatile变量后面的语句放到其前面去执行。

       但是volatile无法保证原子性,比如自增操作,自增操作分为三个子操作:读取变量的原始值、进行加1操作、写入工作内存,且这三个子操作可能会分开执行。

Volatile的实现原理:有volatile变量修饰的共享变量进行操作的时候,会多出一行以Lock为前缀的汇编代码,这个前缀指令在多核处理器下引发两件事:

1>将当前处理器缓存行的数据写回到系统内存;

2>这个写回内存的操作会使得在其他CPU里缓存了该内存地址的数据无效。

使用volatile必须具备以下2个条件:1>对变量的写操作不依赖于当前值;2>该变量没有包含在具有其他变量的不等式中

类加载机制,双亲委派模型,好处是什么?

类加载,JVM第一次使用到这个类的时候,需要对这个类的信息进行加载。一个类只会加载一次,之后将这个类的信息放在堆空间,静态属性放在方法区。JVM类加载器从上到下一共分为三类:1、启动类加载器(Bootstrap ClassLoader)2、扩展类加载器(Extension ClassLoader), 3、 应用程序类加载器(Application ClassLoader)。

类装载器就是寻找类的字节码文件,并构造出类在JVM内部表示的对象组件。在Java中,类装载器把一个类装入JVM中,要经过以下步骤:

     (1) 加载:查找和导入Class文件;

     (2) 链接:把类的二进制数据合并到JRE中;

        (a)校验:检查载入Class文件数据的正确性;

        (b)准备:给类的静态变量分配存储空间;

        (c)解析:将符号引用转成直接引用;

     (3) 初始化:对类的静态变量,静态代码块执行初始化操作

JVM通过双亲委派模型进行类的加载启动类加载器。双亲委派模型的工作工程:

1.该类加载器收到了类加载的请求,

2.将这个请求委派给父类加载器完成

3.若父类加载器反馈无法完成这个加载请求,子类加载器进行加载。

也就是说,所有的请求多会传送到顶层的启动类加载器,从顶层开始试图加载类,无法加载再向下传递。

采用双亲委派的一个好处是不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个Object对象。

接口和抽象类的区别是什么?

接口中全都是抽象方法,抽象类中必须有抽象方法,但也可以有具体方法;

一个类只能实现接口中的抽象方法,使用implements关键字,对于抽象类要继承,使用extends关键字,要提供抽象类中所有声明的实现;

抽象类中可以有构造器,接口中不能有;

抽象类可以用protected,private等修饰符,而接口默认修饰符为public,不能使用其他的;

抽象类中可以有main方法运行,接口中不能有main方法;

抽象方法比接口速度要快,接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。

如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 如果你往接口中添加方法,那么你必须改变实现该接口的类。

接口中的变量只能是public static final变量,抽象类中可以有各种类型的变量;

接口中不能含有静态变量和静态方法,抽象类中可以有;

一个类只可以继承一个抽象类,一个类可以实现多个接口;

HashMap,HashTable和ConcurrentHashMap的区别?

(1)继承结构而言,三者都是继承Map接口的;

(2)存储的内容都是以键值对的形式存储;

异:

(1)线程安全,HashMap不是线程安全的,HashTable和ConcurrentHashMap都是线程安全的;

(2)null值处理,HashMap的key-value都可以为null,HashTable和ConcurrentHashMap的key-value都不能为null;

(3)数据结构,HashMap和HashTable底层都是数组+链表,ConcurrentHashMap底层是数组,数组内部是数组+链表的形式;

(4)初始默认值,HashMap和ConcurrentHashMap数组初始大小为16,HashTable数组初始大小为11;

(5)增长方式,HashMap和ConcurrentHashMap都是2倍扩容,HashTale是1.5倍扩容;

(6)hash计算方法,HahTable和ConcurrentHashMap直接使用key的hashcode值,而hashMap对key的hash值重新计算;

线程池运行流程,参数,策略

运行流程:

1>、当线程池中线程数量小于 corePoolSize 则创建线程,并处理请求。

2>、当线程池中线程数量大于等于 corePoolSize 时,则把请求放入 workQueue 中,随着线程池中的核心线程们不断执行任务,只要线程池中有空闲的核心线程,线程池就从workQueue 中取任务并处理。

3> 、当 taskQueue 已存满,放不下新任务时则新建非核心线程入池,并处理请求直到线程数目达到 maximumPoolSize(最大线程数量设置值)。

4>如果线程池中线程数大于 maximumPoolSize 则使用 RejectedExecutionHandler 来进行任务拒绝处理。

参数

corePoolSize            线程池的核心线程数;

maximumPoolSize   线程池所能容纳的最大线程数;

keepAliveTime         非核心线程闲置时的超时时长;

unitkeepAliveTime   时长对应的单位;

workQueue              线程池中的任务队列;

ThreadFactory          线程工厂;

RejectedExecutionHandler当任务无法被执行时(超过线程最大容量 maximum 并且 workQueue 已经被排满了)的处理策略

处理策略

1)AbortPolicy:直接抛出异常

2)CallerRunsPolicy:只用调用者所在线程来运行任务

3)DiscardOldestPolicy:丢弃队列中最近的一个任务,并执行当前任务。

4)DiscardPolicy:不处理,丢弃掉。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
期末考试题型: 一、 填空题(本题共15空 ,每空1分,共15分。) 二、 单项选择题(本题共20小题,每题1分,共20分。) 三、 是非题(对划“√”,错划“×”,本题共10小题,每题1分,共10分。) 四、 简答题(本题共5小题,每小题5分,共25分。) 五、 程序填空题(本题共5空 ,每空2分,共10分。) 六、 编程题(本题共2小题,每小题10分,共20分。) 二、填空题 1、Java语言是一种完全的_面相对象___程序设计语言。 2、布尔型常量有两个值,它们分别是_true__、_false___。 3、在定义一个方法时,一般都要指明该方法的返回值类型,如果它不返回任何值,则必须将其声明成 void 。 4、在Java的语言环境中已经包含了一组相关的核心类库,它们属于Java.lang包。 5、写出完整的main方法的声明 public static void main(String args[]) 。 6、要设计一个Applet小程序,必须先引入包 java.applet 。 7、设x=2.5,a=7,y=4.7,算术表达式x+a%3*(int)(x+y)%2/4的值为:2.75___ 8、被关键字_final___修饰的方法是不能被当前类的子类重新定义的方法。 9、Java中类成员的限定词有以下几种:private, _protected__, public__, 默认友好。 10、基类的公有成员在派生类中的访问权限由_基类___决定。 11、用static修饰的方法,称为静态方法。它们不是对象的方法,而是整个类的方法。静态方法只能处理用关键字_static___修饰的数据。 12、在Java中有一种叫作__构造方法__的特殊方法,我们在程序中用它来对类的对象成员进行初始化。 13、面向对象技术具有_封装性___、_继承性___、_抽象性___、多态性等特性。 14、Java中所有类都是类 _Object___的子类。 15、顺序执行以下两个语句的输出结果是: 10 。 String s = “我喜欢学习Java!”; System.out.println(s.length( )); 16、据程序的构成和运行环境的不同,Java源程序分为两大类: Application 程序和 Applet 程序。 17、如果一个Java源程序文件中定义有4个类,则使用Sun公司的JDK编译器javac编译该源程序文件将产生 4 个文件名与类名相同而扩展名为 class 的字节码文件。 18、开发与运行Java程序需要经过的三个主要步骤为 编辑源文件 、 编译器编译生成字节码文件 和 解释器执行 。 19、如果一个Java Applet源程序文件只定义有一个类,该类的类名为MyApplet,则类MyApplet必须是 Applet 类的子类并且存储该源程序文件的文件名必须为 MyApplet.java 。 20、 一个Java Application源程序文件名为MyJavaApplication.java,如果使用Sun公司的Java开发工具JDK编译该源程序文件并使用其虚拟机运算这个程序的字节码文件,应该顺序执行如下两个命令: javac MyJavaApplication.javajava MyJavaApplication 。 21、在Java的基本数据类型中,char型采用Unicode编码方案,每个Unicode码字符占用 2 字节内存空间,这样,无论是中文字符还是英文字符,每个都是占用2 字节内存空间。 22、在Java程序中定义的类有两种成员: 静态成员 、 实例成员 。 23、Java源程序是由类定义组成的,每个程序中可以定义若干个类,但是只有一个类是主类。在Java Application中,这个主类是指包含 main 方法的类;在Java Applet里,这个主类是一个系统类 Applet 的子类。 24、创建一个名为 MyPackage 的包的语句是 package MyPackage ; , 该语句应该放在程序的位置为: 程序中非注释行的第一行 。 25、 抽象或abstract 方法是一种仅有方法头,没有具体方法体和操作实现的方法,该方法必须在抽象类之中定义。 最终后final 方法是不能被当前类的子类重新定义的方法。 26、多态是指 一种定义,多种实现 ,在Java中有两种多态,一种是使用方法的 重载 实现多态,另一种是使用方法的 覆盖 实现多态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值