JAVA 多线程(4)
接着3说:
一、String常量池
先回顾 java 的基本数据类型:
变量就是申请内存来存储值。也就是说,当创建变量的时候,需要在内存中申请空间。
内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。
因此,通过定义不同类型的变量,可以在内存中储存整数、小数或者字符。
Java语言提供了八种基本类型。六种数字类型(四个整数型(默认是int 型),两个浮点型(默认是double 型)),一种字符类型,还有一种布尔型
说byte之前说一下别的。计算机码或者语言是二进制也就是 0 和1,为了让计算机能识别人类语言,所以用二进制来定义规则,也就是编码,把人类语言翻译为二进制的数据。
所以这里多记一下:
计算机的计算单位-》
0/1 的单位我们称为bit ,也就是虽小单位,1byte = 8bit ,byte 我们称它为字节,比如 10000001 的大小是1byte ,也就是8bit。byte简称为B。
再往上,就是K,1K = 1024B,我们常说的1KB 意思就是说有1K的B,但是K是1024 不是1000 ,因为计算机是通过二进制来识别计算的,这样计算性能更高。
以此类推 1M = 1025K,1G = 1024 M,1T = 1024G 等等等。
多说依据硬盘空间与网络传输单位,为了方便,一般服务商则采用的是十进制来计算,所以有时候我们买的是10G的硬盘,但是计算机上显示的却比它小。第三方网络服务商也是通过十进制而不是二进制。这点需要注意。
数字型(整数)
byte:
- byte数据类型是8位、有符号的,以二进制补码表示的整数;(256个数字),占1字节
- 最小值是-128(-2^7);
- 最大值是127(2^7-1);
- 默认值是0;
- byte类型用在大型数组中节约空间,主要代替整数,因为byte变量占用的空间只有int类型的四分之一;
- 例子:byte a = 100,byte b = -50。
short:
- short数据类型是16位、有符号的以二进制补码表示的整数,占2字节
- 最小值是-32768(-2^15);
- 最大值是32767(2^15 - 1);
- Short数据类型也可以像byte那样节省空间。一个short变量是int型变量所占空间的二分之一;
- 默认值是0;
- 例子:short s = 1000,short r = -20000。
int(一般我们使用int较多):
- int数据类型是32位、有符号的以二进制补码表示的整数;占3字节
- 最小值是-2,147,483,648(-2^31);
- 最大值是2,147,485,647(2^31 - 1);
- 一般地整型变量默认为int类型;
- 默认值是0;
- 例子:int a = 100000, int b = -200000。
long:
- long数据类型是64位、有符号的以二进制补码表示的整数;占4字节
- 最小值是-9,223,372,036,854,775,808(-2^63);
- 最大值是9,223,372,036,854,775,807(2^63 -1);
- 这种类型主要使用在需要比较大整数的系统上;
- 默认值是0L;
- 例子: long a = 100000L,int b = -200000L。
long a=111111111111111111111111(错误,整数型变量默认是int型)
long a=111111111111111111111111L(正确,强制转换)
如果强制为long 请在变量值后加上L
数字型(浮点)
float:
- float数据类型是单精度、32位、符合IEEE 754标准的浮点数;占4字节 -3.4*E38- 3.4*E38。。。浮点数是有舍入误差的
- float在储存大型浮点数组的时候可节省内存空间;
- 默认值是0.0f;
- 浮点数不能用来表示精确的值,如货币;
- 例子:float f1 = 234.5f。
- float f=6.26(错误 浮点数默认类型是double类型)
- float f=6.26F(转换正确,强制)
- double d=4.55(正确)

double:
- double数据类型是双精度、64位、符合IEEE 754标准的浮点数;
- 浮点数的默认类型为double类型;
- double类型同样不能表示精确的值,如货币;
- 默认值是0.0d;
- 例子:double d1 = 123.4。
布尔型
boolean:
- boolean数据类型表示一位的信息;
- 只有两个取值:true和false;
- 这种类型只作为一种标志来记录true/false情况;
- 默认值是false;
- 例子:boolean one = true。
关于布尔型占用几个字节请参考
https://www.jianshu.com/p/2f663dc820d0
引用上面这位博主的话:
boolean: The boolean data type has only two possible values: true and false. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its "size" isn't something that's precisely defined.
布尔类型:布尔数据类型只有两个可能的值:真和假。使用此数据类型为跟踪真/假条件的简单标记。这种数据类型就表示这一点信息,但是它的“大小”并不是精确定义的。
可以看出,boolean类型没有给出精确的定义,《Java虚拟机规范》给出了4个字节,和boolean数组1个字节的定义,具体还要看虚拟机实现是否按照规范来,所以1个字节、4个字节都是有可能的。这其实是运算效率和存储空间之间的博弈,两者都非常的重要。
字符型
char:
- char类型是一个单一的16位Unicode字符;用 ‘’表示一个字符。。java 内部使用Unicode字符集。。他有一些转义字符 ,2字节
- 最小值是’\u0000’(即为0);
- char数据类型可以储存任何字符;
- 最大值是’\uffff’(即为65,535);可以当整数来用,它的每一个字符都对应一个数字
- 可以存放汉字,字母和数字占一个字节,一个字节8位,中文占2个字节,16位
- char 的值使用单引号 ‘s’
参考地址https://www.cnblogs.com/1130136248wlxk/articles/5105524.html
说完了基本类型,String是什么String是一个类,是引用类型。
重点:
Java为String类型提供了缓冲池机制,当使用双引号定义对象时,Java环境首先去字符串缓冲池寻找内容相同的字符串,如果存在就拿出来使用,否则就创建一个新的字符串放在缓冲池中。
例如: String S=new String("abc''), 产生(或者创建)几个对象?
答案是:产生一个或者两个对象。如果常量池中原来没有“abc",就产两个对象,如果字符串常量池中"abc",就产生一个对象。
因此,这个问题如果换成 String str = new String("abc")涉及到几个String对象?合理的解释是2个。

在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。
在这里要永远记住一点:“String对象一旦被创建就是固定不变的了,对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象”。
字符串常量池:
VM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。
每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串。
其他String的讲解请参考
https://blog.csdn.net/qauchangqingwei/article/details/80831797
所以~ 字符串是具有缓存机制的,多线程中如果使用string最晚lock锁,可能会出现以下问题:
使用不同的锁建立异步机制,但是结果是使用同一个锁:
public static void main(String[] args) {
Test2 test2 = new Test2();
String a;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
test2.judge("A","AA");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
test2.judge("A","BB");
}
});
t.start();
t2.start();
}
public void judge(String what,String param) {
synchronized (what) {
while (true){
System.out.println(param);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出结果:

线程t2 的没有抢到资源,因为同步锁(对象监视器是“A”),线程A和线程B的锁实际上是同一个锁,因为String的缓存机制,“A”在编译器就被放在字符串常量池中,导致实际指向的是同一个对象。
如果使用new String 的方式就没问题了,问new String 实际上会在堆中再创建一个对象。
二、死锁
当程序中出现某一个线程等待一个永远都不会释放的锁时,就会出现死锁。
例如2个线程A和B,调用同一个实例对象的方法C和方法D,方法C和D中使用同步块绑定了对象锁E和F。
或者说有一个锁A,线程A和线程B要用用,但是锁A是永远不会释放~咋整- 死锁。
public static void main(String[] args) {
TestThread testThread = new TestThread();
Thread t = new Thread(testThread,"线程A");
Thread t2 = new Thread(testThread,"线程B");
testThread.setUsername("A");
try {
t.start();
Thread.sleep(100);
testThread.setUsername("B");
t2.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class TestThread implements Runnable {
private String username;
Object a = new Object();
Object b = new Object();
public void setUsername(String username) {
this.username = username;
}
@Override
public void run() {
if (username.equals("A")) {
synchronized (a) {
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
System.out.println("A OVER");
}
}
} else {
synchronized (b) {
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
System.out.println("B OVER");
}
}
}
}
}
输出:

没有OVER ,线程A在等线程B的对象锁b,线程B在等线程A的对象锁a。
查询:
通过到jdk的bin目录查询状态。


由此监测到了死锁状态。
JAVA 多线程(4)的更多相关文章
- 40个Java多线程问题总结
前言 Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多.越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的.这篇文章主要是对多线程的问题进行 ...
- Java多线程基础知识篇
这篇是Java多线程基本用法的一个总结. 本篇文章会从一下几个方面来说明Java多线程的基本用法: 如何使用多线程 如何得到多线程的一些信息 如何停止线程 如何暂停线程 线程的一些其他用法 所有的代码 ...
- Java多线程系列--“JUC锁”03之 公平锁(一)
概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...
- Java多线程系列--“JUC锁”04之 公平锁(二)
概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...
- Java多线程--让主线程等待子线程执行完毕
使用Java多线程编程时经常遇到主线程需要等待子线程执行完成以后才能继续执行,那么接下来介绍一种简单的方式使主线程等待. java.util.concurrent.CountDownLatch 使用c ...
- Java多线程 2 线程的生命周期和状态控制
一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就 ...
- java 多线程 1 线程 进程
Java多线程(一).多线程的基本概念和使用 2012-09-10 16:06 5108人阅读 评论(0) 收藏 举报 分类: javaSE综合知识点(14) 版权声明:本文为博主原创文章,未经博 ...
- 一起阅读《Java多线程编程核心技术》
目录 第一章 Java多线程技能 (待续...)
- 第一章 Java多线程技能
1.初步了解"进程"."线程"."多线程" 说到多线程,大多都会联系到"进程"和"线程".那么这两者 ...
- java从基础知识(十)java多线程(下)
首先介绍可见性.原子性.有序性.重排序这几个概念 原子性:即一个操作或多个操作要么全部执行并且执行的过程不会被任何因素打断,要么都不执行. 可见性:一个线程对共享变量值的修改,能够及时地被其它线程看到 ...
随机推荐
- (转载)Javascript 中的非空判断 undefined,null, NaN的区别
原文地址:https://blog.csdn.net/oscar999/article/details/9353713 在介绍这三个之间的差别之前, 先来看一下JS 的数据类型. 在 Java ,C ...
- Kali学习笔记13:操作系统识别
为什么要扫描操作系统呢? 其实和上一篇博客:<服务扫描>类似,都是为了能够发现漏洞 发现什么漏洞? 不同的操作系统.相同操作系统不同版本,都存在着一些可以利用的漏洞 而且,不同的系统会默认 ...
- 一些能体现个人水平的SQL语句[总结篇]
作为一名小小的开发人员,刚入门的时候觉得很难,过了一段时间之后,发现很简单,很快就可以搞定很bug了.然而这并不能说明你就已经很牛掰了,只能说,你不了解其他太多的东西.应该说,数据库有几个共同的命令, ...
- Spark基础-scala学习(二、面向对象)
面向对象编程之类 //定义一个简单的类 scala> :paste // Entering paste mode (ctrl-D to finish) //类默认public的 class He ...
- 【Spark调优】聚合操作数据倾斜解决方案
[使用场景] 对RDD执行reduceByKey等聚合类shuffle算子或者在Spark SQL中使用group by语句进行分组聚合时,经过sample或日志.界面定位,发生了数据倾斜. [解决方 ...
- alibaba的FastJson找不到JSON对象问题
在现在出现使用JSON.toJsonString()方法时,可能没有JSON这个对象. 这种问题可能是下载的jar版本比较高.在低版本的jar使用的是JSON对象. 我使用的是1.2.47版本的jar ...
- redux源码学习笔记 - combineReducers
上一篇有了解到,reducer函数的两个为:当前state和此次dispatch的action. state的结构是JavaScript对象,每个key都可以代表着不同意义的数据.比如说 { list ...
- Java 程序员必备的 15 个框架,前 3 个地位无可动摇!
Java 程序员方向太多,且不说移动开发.大数据.区块链.人工智能这些,大部分 Java 程序员都是 Java Web/后端开发.那作为一名 Java Web 开发程序员必须需要熟悉哪些框架呢? 今天 ...
- SVN切换账号
问题背景 SVN账号在登录的时候,默认是保存在个人电脑的 C:\Users\Administrator\AppData\Roaming\Subversion\auth\svn.simple\ 目录下的 ...
- Python编程Day7——字符编码、字符与字节、文件操作
一.字符编码 重点 ***** 1. 什么是字符编码:将人识别的字符转换计算机能识别的01,转换的规则就是字符编码表2. 常用的编码表:ascii.unicode.GBK.Shift_JIS.Euc- ...