什么是ThreadLocal,ThreadLocal有什么作用

根据JDK文档中的解释:ThreadLocal的作用是提供线程内的局部变量,这种变量在多线程环境下访问时能够保证各个线程里变量的独立性。

从这里可以看出,引入ThreadLocal的初衷是为了提供线程内的局部变量,而不是为了解决共享对象的多线程访问问题。实际上,ThreadLocal根本就不能解决共享对象的多线程访问问题。

每个线程中可以持有很多个ThreadLocal对象,这些对象通过hash后存储在Thread的ThreadLocalMap中,其中的Key为ThreadLocal对象,value为该对象在本线程中的一个副本。ThreadLocal本身并不存储value值,只是作为key在ThreadLocalMap中索引value值

每个Thread含有的ThreadLocalMap中的Key为ThreadLocal变量的弱引用,如果一个ThreadLocal变量没有外部强引用来引用它,那么它在JVM下一次GC的时候会被垃圾回收掉,这时候,Map中就存在了key为NULL的value,这个value无法被访问。如果当前线程再迟迟不结束的话(例如当前线程在一个线程池中),那么value所指向的对象可能永远无法释放,也即不能被回收,造成内存泄露。
ThreadLocalMap的设计者很显然也想到了这个问题,所以其在每一次对ThreadLocalMap的set,get,remove等操作中,都会清除Map中key为null的Entry。因此,ThreadLocal一般是不会存在内存泄露风险的。
但是,将清除NULL对象的工作交给别人,并不是一个明智的选择,所以聪明的你,在Thread中使用完ThreadLocal对象后,一定要记得调用ThreadLocal的remove方法,进行手动清除。

示例代码

* JDK Version:1.8 
 */  
public class ThreadLocalTest {  
    private static final ThreadLocal<Integer> local = ThreadLocal.withInitial(()->0);  
    public static void main(String[] args) throws InterruptedException {  
        for(int i = 0; i < 10;i += 3){  
            new MyThread(i).start();  
        }  
    }  

    static class MyThread extends Thread{  
        private int end;  

        public MyThread(int end) {  
            this.end = end;  
        }  

        @Override  
        public void run() {  
            System.out.println(Thread.currentThread().getName() + " start, local = " + local.get());  
            for(int i = 0; i < end;i++){  
                local.set(local.get() + i); //计算(end+1)*end/2的值  
            }  
            System.out.println(Thread.currentThread().getName() + " start, local = " + local.get());  
        }  
    }  
}

输出结果

Thread-0 start, local = 0
Thread-2 start, local = 0
Thread-1 start, local = 0
Thread-2 start, local = 21
Thread-3 start, local = 0
Thread-0 start, local = 0
Thread-3 start, local = 45
Thread-1 start, local = 6

Linux的常用命令

1.命令格式与目录处理命令

ls –a【查看隐藏文件】
ls –l【查看文件信息长格式显示】
ls –d【查看指定目录的详细信息】
ls –h【显示容量大小】
ls –i【查看任何文件的I 节点】
ll 文件名【查看一个文件的详细信息】

2.目录处理命令

mkdir –p【递归创建目录】
cd【切换指定目录】
pwd【显示当前目录】
rmdir【删除空目录】
cp【复制文件到某个目录下】
cp –r【复制目录】
cp –p【保留文件属性】
mv【剪切文件、改名】
rm【删除文件】
rm –r【删除目录】
rm –f【强制执行】

3.文件处理命令

touch【创建空文件】
cat【查看文件内容】
cat –n【显示行号】
tac【显示文件内容(反向列示)】
more【分页显示文件内容(空格或f[翻页], Enter[换行], q或Q[退出])】
less【分页显示文件内容(可向上翻页),填写/可搜索关键词,n等于next,PageUp和PageDown】
head【显示文件前面几行】
head -n【指定行数,head –n 20 /etc/services】
tail【显示文件后面几行】
tail –n【指定行数】
tail –f【动态显示文件末尾内容】

4.链接命令

ln【生成链接文件,类似拷贝,可以同步更新】
ln –s【创建软链接,相当于快捷方式】

5. 网络命令

write 用户名【给在线用户发信息,以Ctrl+D保存结束】
wall 信息【发广播信息】
ping -c 4 IP地址【测试网络连通性,-c:指定发送次数为4次】
ifconfig eth0 192.168.0.169【查看和设置网卡信息】
mail 用户名【查看发送电子邮件,以Ctrl+D保存结束,help查看信息】
last【列出目前与过去登入系统的用户信息】
lastlog -u 502【检查某特定用户上次登录的时间】
traceroute 网址【显示数据包到主机间的路径 IP等等】
netstat -t/-u/-l/-r/-n【显示网络相关信息,-t:TCP协议,-u:UDP协议,-l:监听,-r:路由,-n:显示IP地址和端口号】
netstat -tlun【查看本机监听的端口】
netstat -an【查看本机所有的网络】
netstat -rn【查看本机路由表】
mount【挂载命令—详细找百度吧】
mount /dev/sr0 /mnt/cdrom/【挂载光盘】
umount /dev/sr0【卸载挂载点】

6. 用户管理命令

useradd 用户名【添加新用户】
passwd 用户名【设置用户密码】
who【查看登录用户信息,tty本地登录,pts远程终端】
w【查看登录用户的详细信息,全】

7. 压缩解压命令

gzip 文件【压缩文件,压缩后的格式:.gz】
gunzip 文件【解压.gz的压缩文件】
tar -zcf temp.tar.gz temp【打包目录,-c:打包,-v:显示详细信息,-f:指定文件名,-z:打包同时压缩,temp:文件名】
tar -zxf temp.tar.gz【解压目录,-x:解包,-v:显示详细信息,-f:指定文件名,-z:解包同时解压,temp:文件名】
zip -r temp.zip temp【压缩问价或目录,-r:压缩目录,temp:文件名】
unzip temp【解压.zip的压缩文件,temp:文件名或目录】
bzip2 -k temp【压缩文件,-k:产生压缩文件后保留原文件,temp:文件名】
bunzip2 -k temp【解压文件,-k:解压缩后保留原文件,temp:文件名】
tar -cjf temp.tar.bz2 temp【压缩】
tar -xjf temp.tar.bz2【解压】

8. 网络命令

write 用户名【给在线用户发信息,以Ctrl+D保存结束】
wall 信息【发广播信息】
ping -c 4 IP地址【测试网络连通性,-c:指定发送次数为4次】
ifconfig eth0 192.168.0.169【查看和设置网卡信息】
mail 用户名【查看发送电子邮件,以Ctrl+D保存结束,help查看信息】
last【列出目前与过去登入系统的用户信息】
lastlog -u 502【检查某特定用户上次登录的时间】
traceroute 网址【显示数据包到主机间的路径 IP等等】
netstat -t/-u/-l/-r/-n【显示网络相关信息,-t:TCP协议,-u:UDP协议,-l:监听,-r:路由,-n:显示IP地址和端口号】
netstat -tlun【查看本机监听的端口】
netstat -an【查看本机所有的网络】
netstat -rn【查看本机路由表】
mount【挂载命令—详细找百度吧】
mount /dev/sr0 /mnt/cdrom/【挂载光盘】
umount /dev/sr0【卸载挂载点】

Vim命令

1).vim常用操作

vim 文件名【进入或新建–进入命令模式】
i/a/o【进入插入模式,a:在光标所在字符后插入,A:在光标所在行尾插入,i:在光标所在字符前插入,I:在光标所在行行首插入,o:在光标下插入新行,O:在光标上插入新行】

:set nu【添加行号】
:set nonu【取消行号】
gg【到第一行】
G【到最后一行】
nG【到第n行】
:n【到第n行——–推荐】
$【移至行尾】
0【移至行首】

x【删除光标所在处字符———–推荐】
nx【删除光标所在处后n个字符】
dd【删除光标所在行,ndd删除n行——–推荐】
dG【删除光标所在行到文件末尾内容】
D【删除光标所在处到行尾内容】
:n,nd【删除指定范围的行】

yy【复制当前行————推荐】
nyy【复制当前行一下n行】
dd【剪切当前行】
ndd【剪切当前行以下n行】
p/P【粘贴在当前光标所在行下(p)或行上(P)——–推荐】

r【取代光标所在处字符】
R【从光标所在处开始替换字符,按ESC结束】
u【取消上一步操作,撤销———-推荐】

/string【搜索指定字符串,string:字符串,n:搜索指定字符串的下一个出现位置】
:set ic【搜索时忽略大小写】
:set noic【取消搜索时忽略大小写】
:%s/old/new/g【全文替换指定字符串,冒号指全文替换,%s:全文搜索,old:要替换的字符串,new:替换的新的字符串,g:不询问确认】
:n,ns/old/new/c【在一定范围内替换指定字符串,(n,ns:起始行,终止行s),c:询问确认】

:w【保存修改——推荐】
:w /tmp/temp.txt【另存为指定文件】
:wq【保存退出———推荐】
:q!【不保存退出】
ZZ【快捷键,保存修改并退出】
:wq!【保存修改并退出(文件所有者及root可使用)】

按ESC【退出模式,进入命令模式】
2).vim使用技巧

:r /tmp/temp.txt(被导入的文件)【把temp.txt的内容导入到光标处】
:r !date(命令)【可以在不退出vim的情况下,执行相应的操作命令,date:系统时间命令】
:map ^P I#【定义快捷键:map,^P:按ctrl+v+p(快捷键按Ctrl+p),注释该行】
:map ^B 0x【定义快捷键:map,^B:按ctrl+v+b(快捷键按Ctrl+b),取消注释该行】
:1,4s/^/#//g【多行注释,把1到4行的行首添加#】
:1,4s/^#//g【取消多行注释,把1到4行的行首的#去掉】
:1,4s/^/\/\//g【多行注释,把1到4行的行首添加//】
:1,4s/^\/\//g【取消多行注释,把1到4行的行首的//去掉】
:ab mymail www.xxx@163.com【替换,在编辑时填写mymail回车时就会被替换成邮箱】

快捷键或编辑模式命令 在重启后会失效,必须在/root/.vimrc或/home/*/.vimrc目录下才会被永久保存—注意填写时不用填写:了

更多常用命令参考

取出一个部门中高于部门平均工资的数据

Java基础知识软考 java基础笔试题在线考_Java基础知识软考

SELECT emp.* from emp, (select deptno,AVG(sal) sal  from emp GROUP BY deptno)as emp1
where emp.deptno  =emp1.deptno AND emp.sal>emp1.sal

简述数据库索引的作用。

作用

:这是因为,创建索引可以大大提高系统的性能。
第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
第二,可以大大加快 数据的检索速度,这也是创建索引的最主要的原因。
第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
第四,在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

补充:

(1)创建索引的不利。

第一,创建索引和维护索引要耗费时间,这种时间随着数据 量的增加而增加。
第二,索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
第三,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

(2)索引是建立在数据库表中的某些列的上面。

因此,在创建索引的时候,应该仔细考虑在哪些列上可以创建索引,在哪些列上不能创建索引。一般来说,应该在这些列上创建索引,例如:
① 在哪些列上可以创建索引
在经常需要搜索的列上,可以加快搜索的速度;
在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
在经常用在连接的列上,这 些列主要是一些外键,可以加快连接的速度;
在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
在经常需要排序的列上创 建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
② 哪些列上不能创建索引
同样,对于有些列不应该创建索引。一般来说,不应该创建索引的的这些列具有下列特点:
第一,对于那些在查询中很少使用或者参考的列不应该创建索引。这是因 为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
第二,对于那 些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比 例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
第三,对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
第四,当修改性能远远大于检索性能时,不应该创建索 引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因 此,当修改性能远远大于检索性能时,不应该创建索引。

简述抽象类与接口的区别

答:① 抽象类是对事物的抽象(类的抽象),是一种模板式设计,而接口是对行为的抽象,是一种行为规范,是一种辐射式设计;
② 抽象类中既可以定义抽象方法也可以定义非抽象方法,而接口中只能定义抽象方法;
③ 抽象类中可以有成员变量(包含静态成员变量)、属性、常量,并且它们可以是非公共的;而接口中成员变量只能是public static final类型的,属性只能是公共的;
④ 抽象类中可以有静态代码块和静态方法,而接口中不能含有静态代码块和静态方法;
⑤ 一个类只能继承一个抽象类,而一个类却可以实现多个接口;

统计字符串中各字符个数

public static void count(String str){
Map<String,Integer> map=new HashMap<String,Integer>(); 
for(char ch:str.getChars()) {
    String ss=String.valueOf(ch); 
Integer count=map.get(ss); 
if(count==null)  
count=1; 
map.put(ss,count); 
} 
for(String st:map.keys()) {
 System.out.println(st+":"+map.get(st)); }
}

输入一个正整数,按逆序输出

public class ExaminationOne {
    public static void main(String[] args) {
        ExaminationOne test=new ExaminationOne();
        System.out.println(test.reverse(12345));
    }
     int reverse(int source){
List<Integer> lt =new LinkedList<Integer>();
int n = source;
        while(n!=0) {
            int i = n%10;
            n = n/10;
            lt.add(i);
        }
        int count = lt.size();
    int res=0;
    for(int i=0;i<count;i++)
        {
            int m=1;
            for(int j=i+1;j<count;j++)
            {
                m=m*10;
            }
            res= res+lt.get(i)*m;}

        return res;
    }
}

简述ArrayList,Vector, LinkedList的区别和特性

答:ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所
以插入速度较快。

线程安全是指什么?

答:线程安全就是代码所在的进程中的多线程访问同一代码,不会产生不确定的结果。

线程间如何通信?进程间如何通信?

答:线程间通信:由于多线程共享地址空间和数据空间,所以多个线程间的通信是一个线程的数据可以直接提供给其他线程使用,而不必通过操作系统(也就是内核的调度)。
进程间的通信则不同,它的数据空间的独立性决定了它的通信相对比较复杂,需要通过操作系统。以前进程间的通信只能是单机版的,现在操作系统都继承了基于套接字(socket)的进程间的通信机制。这样进程间的通信就不局限于单台计算机了,实现了网络通信。