JAVA流程控制
Scanner
next()方法
- 一定要读取到有效字符后才可以结束输入。
- 对输入有效字符之前遇到的空白,next()方法会自动将其去掉
- 只有输入有效字后才将其后面输入的空白作为分隔符或者结束符。
- next() 不能得到带有空格的字符串
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容"); //输入内容:hello word
if (scanner.hasNext()){ //判断用户有没有输入 循环会用到现在用不到
String s = scanner.next(); //使用next方法接收
System.out.println(s); // = hello
}
scanner.close(); //属于IO流的如果不关闭回一直占用资源
nextLine()方法
- 以Enter为结束符,也就是说NextLine()方法返回的时输入回车之前的所有字符。
- 可以获得空白。
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容"); //输入内容:hello word
if (scanner.hasNextLine()){ //判断用户有没有输入 循环会用到
String s = scanner.nextLine(); //使用nextLine方法接收
System.out.println(s); // = hello word
}
scanner.close(); //属于IO流的如果不关闭回一直占用资源
检测输入类型
Scanner scanner = new Scanner(System.in);
if (scanner.hasNextInt()){
System.out.println("数字");
}else if (scanner.hasNextDouble()){
System.out.println("小数");
}else if (scanner.hasNextLine()){
System.out.println("字符");
}else {
System.out.println("s");
}
scanner.close();
限定输入类型while
Scanner scanner = new Scanner(System.in);
double sum = 0; //计算输入的总和
int m = 0; //计算输入了多少次
while (scanner.hasNextDouble()){ //判断输入是否为double型 如果输入字符串就结束循环
double x = scanner.nextDouble();
m = m+1;
sum = sum + x;
System.out.println("m:"+m+" sum:"+sum);
}
scanner.close();
if选择结构
int s = 10;
if (s == 10){
System.out.println("s=10");
}else if (s == 20){
System.out.println("s=20");
}else {
System.out.println("s=不知道");
}
switch选择结构
//JDK7以后可以用字符串
char grade = 'a';
switch (grade){
case 'A':
System.out.println("优秀");
break;
case 'B':
System.out.println("良好");
break;
default:
System.out.println("未知等级");
}
循环结构
while循环
- 只要布尔表达式为true,循环就会一直执行下去
while (布尔表达式){
}
do while循环
- do while 循环和while类似 不同的是do while循环至少会执行一次
- do while 循环是先循环在判断
do {
}while (布尔表达式);
For循环
for (int i=初始值;i<=最大值;i++更新){
}
九九乘法表
for (int j=1;j<=9;j++){
for (int i= 1;i<=j;i++){
System.out.print(j+"*"+i+"="+(j*i)+"\t");
}
System.out.println();
}
增强for循环
int[] number = {10,20,30,40,50};
for (int x : number){
System.out.println(x);
}
break、continue、goto
-
break: 在任何循环语句的主体部分,均可用break控制循环的流程。用于强行退出循环,不执行循环中剩余语句。
-
continue:用于在循环语句体中。用于终止某次循环过程,跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定
-
goto: 标签
outer:for (int i=101;i<150;i++){ for (int j=2;j<i/2;j++){ if (i%j == 0) continue outer; } System.out.println(i+""); }
方法
public static void main(String[] args) {
max(12,32);
}
private static int max(int num1, int num2) {
int s = 0;
if (num1 == num2) {
System.out.println("num1=num2");
return 0; //return 0; 终止方法
}
if (num1>num2){
s = num1;
}else {
s = num2;
}
System.out.println(s);
return s;
}
break return区别
return : 结束方法返回一个结果
break :跳出
调用方法
public static void main(String[] args) {
Demo demo = new Demo();
System.out.println(demo.syHello());
}
public String syHello(){
return "Hello";
}
可变参数方法
public static void main(String[] args) {
test(1,2,3,4,5,6,7);
}
public static void test(int... i){
int s = i.length;
for (int i1 = 0; i1 < i.length; i1++) {
System.out.println(i[i1]);
}
}
递归
public static void main(String[] args) {
System.out.println(f(5)); //==120
}
public static int f(int n){ //= 5*4*3*2*1 = 120
if (n==1){
return 1;
}else {
return n*f(n-1);
}
}
数组
int[] a = {1,2,3}; //静态初始化
arr = new int[3]; //创建一个数组 动态初始化
arr[0] = 12; //给0号赋值1
arr[1] = 22; //给1号赋值1
arr[2] = 32; //给2号赋值1
System.out.println(arr.length); //数组的长度
for (int i = 0; i < arr.length; i++) { //打印数组数据
System.out.println(arr[i]);
}
数组类
public static void main(String[] args) {
Man[] men = {new Man(),new Man()};
}
static class Man{
}
for-Each
int[] arr = {1,2,3,4,5};
for (int i : arr) {
System.out.println(i);
}
数组反转
public static void main(String[] args) {
int[] a = {1,2,3};
reverse(a);
}
private static int[] reverse(int[] a) {
int [] result = new int[a.length];
for (int i=0,j=result.length-1;i<a.length;i++,j--){
result[j] = a[i];
}
for (int i = 0; i < result.length; i++) {
System.out.println(result[i]);
}
return result;
}
二维数组
int [][] arr = {{1,2},{2,3},{3,4}};
System.out.println(arr[1][0]); //=2
System.out.println(arr[1][1]); //=3
System.out.println(arr.length); //=3
System.out.println(arr[0].length); //=2
for (int i=0;i< arr.length;i++){
for (int j=0;j<arr[i].length;j++){
System.out.println(arr[i][j]);
}
}
打印数组Arrays类
int[] a = {1,2,3,4,512,134,123};
System.out.println(Arrays.toString(a)); // = [1, 2, 3, 4, 512, 134, 123]
int[] a = {1,2,3,4,512,134,123};
Arrays.fill(a,1); // = [1, 1, 1, 1, 1, 1, 1] 数组所有内容填充1
Arrays.fill(a,2,4,1); // = [1, 2, 1, 1, 512, 134, 123] 2-4数组被填充为1
System.out.println(Arrays.toString(a)); //打印数组
冒泡排序
public static void main(String[] args) {
int[] arr = {2,3,12,3,13,342};
sort(arr);
System.out.println(Arrays.toString(arr));
}
public static int[] sort(int[] array){
int temp = 0;
for (int i = 0; i <array.length-1; i++) {
for (int j=0;j<array.length-1;j++){
if (array[j+1]>array[j]){ //if (array[j+1]>array[j]) 由大到小排序
temp = array[j]; //if (array[j+1]<array[j]) 由小到大排序
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
return array;
}
优化过
public static void main(String[] args) {
int[] arr = {2,3,12,3,13,342};
sort(arr);
System.out.println(Arrays.toString(arr));
}
public static int[] sort(int[] array){
int temp = 0;
for (int i = 0; i <array.length-1; i++) {
boolean flag = false;
for (int j=0;j<array.length-1;j++){
if (array[j+1]<array[j]){
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
flag = true;
}
}
if (flag == false){
break;
}
}
return array;
}
稀疏数组
int [][] arr1 = new int[11][11]; //创建一个11行11列的数组
arr1[1][2] = 1; //在第1行第2列插入1
arr1[2][3] = 2; //在第2行第3列插入2
for (int[] ints : arr1) { //将所有值打印出来
for (int anInt : ints) {
System.out.print(anInt+"\t");
}
System.out.println();
}
int s = 0;
for (int i = 0; i < arr1.length; i++) { //找出不为0的数组有多少个
for (int i1 = 0; i1 < arr1.length; i1++) {
if (arr1[i][i1] !=0){
s++;
}
}
}
System.out.println("有效值的个数"+s);
面向对象
方法
实例化类
public static void main(String[] args) {
Student student = new Student(); //实例化这个类 通过new出来
student.say(); //对象类型 对象名 = 对象值
}
public class Student {
public void say(){
System.out.println("学生");
}
}
static
加上静态变量可以直接用类名调用
没加静态 必须 new
静态方法和类一起加载 非静态方法必须调用
public class Demo {
public static void main(String[] args) {
a(); //方法a可以直接调用
Demo demo = new Demo();
demo.b(); //方法b要通过创建对象的方法才可以使用
}
public static void a(){ //加上static当创建Demo的时候就已经加载了
}
public void b(){ //不加static 必须通过 new 调用的方式加载
}
}
public class Demo {
{ //2运行
System.out.println("匿名代码块");
}
static { //首先运行 //只会再创建的时候执行一次
System.out.println("静态代码块");
}
public Demo() { //3 构造方法
System.out.println("构造方法");
}
public static void main(String[] args) {
Demo demo = new Demo(); //=静态代码块
} //匿名代码块
} //构造方法
引用传递:
public class Demo {
public static void main(String[] args) {
Stud stud = new Stud();
System.out.println(stud.name); //=s
Demo.change(stud);
System.out.println(stud.name); //=123
}
public static void change(Stud stud){
stud.name = "123";
}
}
class Stud{
String name = "s";
}
构造器
public static void main(String[] args) {
Student student = new Student(); //无参构造 会调用Student的方法如果没有会自动生成一个无参方法
System.out.println(student.string); //= guan
Student student1 = new Student("xin"); //有参构造
System.out.println(student1.string); //= xin
}
public class Student {
public String string;
public Student() {
this.string = "guan";
}
public Student(String string) {
this.string = string;
}
}
继承
每个类默认继承Object的类只是隐藏了
子类继承父类的所有方法,父类的private子类不可以调用
创建对象
--------Teacher
public class Teacher {
public Teacher(){
System.out.println("Teacher");
}
}
--------Student
public class Student extends Teacher{
public Student(){
System.out.println("Student"); //创建方法时也会调用父类的方法 会有一个隐藏的super()对象 不能使用this
}
}
--------Demo
public class Demo {
public static void main(String[] args) {
Student student = new Student(); //= Teacher 先调用父类再调用子类
// Student
}
}
子类方法和父类方法调用
------Teacher
public class Teacher {
public void show(){
System.out.println("sss");
}
}
-----Student
public class Student extends Teacher{
public String name = "wo";
public void stud(){
System.out.println("xuesheng");
}
}
------Demo
public class Demo {
public static void main(String[] args) {
Student student = new Student();
student.stud();
student.show();
System.out.println(student.name);
}
}
Super
super可以强制调用父类的方法 重名可以
注意点:
- super调用父类的构造方法,必须再构造方法的第一个
- suiper必须再子类的方法或者构造方法中
- super 和 this 不能同时调用
-----Teacher
public class Teacher {
public String name = "guangxin";
}
--------Student
public class Student extends Teacher{
private String name = "guan";
public void test(String name){
System.out.println(name); //调用方法里的属性 = guan1
System.out.println(this.name); //加this = 调用类里面的属性 = guan
System.out.println(super.name); //supoer = 调用父类的属性 = guanxin
}
}
------Demo
public class Demo {
public static void main(String[] args) {
Student student = new Student();
student.test("guan1"); //调用子类的test方法
}
}
super与this 构造方法
代表的对象不同
- this :本身调用者这个对象
- super:代表父类对象的应用
前提
- this:没有继承也可以使用
- super: 只有继承才可以使用
构造方法
- this : 本类的构造
- super:父类的构造
加上静态方法
加上静态可以直接用类名调用 B.test();
public class B {
public static void test(){
System.out.println("B_test");
}
}
public class A extends B{
public static void test(){
System.out.println("A_test");
}
}
public static void main(String[] args) {
A a = new A();
a.test(); // = A_test 调用A类的静态方法
A.test(); // = A_test
B b = new A(); //父类的引用指向子类
b.test(); // = B_test
}
重写
父类的静态方法不能被重写
b是A new 出来的对象,因此调用了A方法没有static时,b调用的时对象的方法,而b时用A类new的
因为静态方法时类的方法 ,而非静态是对象的方法
有static时 b调用了B的类的方法 因为b是b类定义的
子类方法和父类的方法必须一致 方法体不同
修饰符
可以扩大但是不能缩小 public > protected > private
public class B {
public void test(){
System.out.println("B_test");
}
protected void ts(){
System.out.println("B");
}
}
public class A extends B{
//Override 重写
@Override //注解:有功能的注释
public void test() {
System.out.println("A"); //重写test方法会有 super.test(); 方法 删了重写就会调用子类的方法了
}
@Override
protected void ts() {
System.out.println("AA"); //重写父类的ts方法
}
}
public static void main(String[] args) {
A a = new A();
a.test(); //=A
B b = new A(); //子类重写了父类的方法
b.test(); //=A
b.ts(); // = AA
}
多态
子类调用的方法都是自己的 或者继承父类的
父类可以指向子类 但是不能调用子类独有的方法
public class Person {
public void run(){
System.out.println("run");
}
}
public class Student extends Person {
public void eat(){
System.out.println("ear");
}
}
public static void main(String[] args) {
Student s1 = new Student();
Person s2 = new Student();
s1.eat(); // = ear 子类调用的方法都是自己的 或者继承父类的
((Student) s2).eat(); // = ear 父类可以指向子类 但是不能调用子类独有的方法 只能强转成子类
}
instanceof
instanceof判断类型是否相似
父类引用指向子类对象
把子类转成父类,向上转型
把父类转换子类,向下转型 : 强制转换
----Teacher
public class Teacher extends Person{
}
----Person
public class Person {
}
----Student
public class Student extends Person {
}
public static void main(String[] args) {
Object object = new Student(); //终极父类
System.out.println(object instanceof Student); //= true
System.out.println(object instanceof Person); //= true
System.out.println(object instanceof Object); //= true
System.out.println(object instanceof Teacher); //= false 因为Teacher跟Student无关
System.out.println(object instanceof String); //= false
Person object1 = new Student(); //终极父类
System.out.println(object1 instanceof Student); //= true
System.out.println(object1 instanceof Person); //= true
System.out.println(object1 instanceof Object); //= true
System.out.println(object1 instanceof Teacher); //= false 因为Teacher跟Student无关
//System.out.println(object1 instanceof String); //= false 编译报错
Student student = new Student();
System.out.println(student instanceof Student); //= true
System.out.println(student instanceof Person); //= true
System.out.println(student instanceof Object); //= true
//System.out.println(student instanceof Teacher); //= false 编译报错
//System.out.println(object1 instanceof String); //= false 编译报错
}
抽象类abstract
继承抽象类必须实现抽象类里面的所有方法
继承只能单继承 接口 可以多继承
抽象类不能new出来只能靠子类去实现他
实现抽象类
----Action
public abstract class Action {
public abstract void doSomething(); //只有抽象方法名字 没有方法实现 在调用方法里面实现
}
public class Demo extends Action{ //抽象类的所有方法,继承了他的子类都必须要实现他的方法
public static void main(String[] args) {
Demo demo = new Demo();
demo.doSomething(); // = ss
}
@Override
public void doSomething() {
System.out.println("ss");
}
}
实现抽象的子子类
----Action
public abstract class Action {
public abstract void doSomething(); //只有抽象方法名字 没有方法实现 在调用方法里面实现
}
----Person
public abstract class Person extends Action{ //抽象类的所有方法继承了他的子类必须要实现他的方法 除非子类也是一个抽象方法
public abstract void show();
}
----Demo
public class Demo extends Person{ //继承Person时就要实现父类Person的所有方法和Action的所有方法
@Override
public void doSomething() {
}
@Override
public void show() {
}
}
通过new抽象类
----Action
public abstract class Action {
public abstract void doSomething(); //只有抽象方法名字 没有方法实现 在调用方法里面实现
}
----
public static void main(String[] args) {
Action s = new Action() {
@Override
public void doSomething() {
System.out.println("s"); //实现抽象类
}
};
s.doSomething(); //调用抽象类
}
方法2
new Action() { //也可以通过这种方法调用
@Override
public void doSomething() { //实现抽象方法
System.out.println("s");
}
}.doSomething(); //调用抽象类
interface接口
作用
- 约束
- 定义一些方法让不同的方法让不同的人实现
- 接口不能实例化接口没有构造方法
- implements可以实现多个接口
----UserService
public interface UserService { //接口中所有定义都是抽象的
//public abstract void run(); 接口中默认都是 public abstract 所不用写
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
----TimeService
public interface TimeService {
void time();
}
----UserServiceImpl //实现接口的所有方法 一般都用Impl结尾
public class UserServiceImpl implements UserService,TimeService{
//实现接口的类就需要重写接口中的方法
//可以实现多继承
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void time() {
}
}
----Main方法
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl(); //直接new出对象就可以使用了
userService.add("1");
userService.delete("1");
}
内部类
----Demo
public class Demo {
private int id = 1;
public void out(){
System.out.println("外部类的方法");
}
public class Inner{
public void in(){
System.out.println("内部类");
}
public void getID(){
System.out.println(id);
}
}
}
-----Test
public class Test {
public static void main(String[] args) {
Demo demo = new Demo();
demo.out(); // = 外部类的方法
Demo.Inner inner = demo.new Inner();
inner.getID();
inner.in();
}
}
public class Test {
public static void main(String[] args) {
new Apple().eat();
new UserService(){
@Override
public void hello() {
}
};
}
}
class Apple{
public void eat(){
System.out.println("1");
}
}
interface UserService{
void hello();
}
Object
java中所有类都要继承Object
Object是一个类,也是所有类的根
我们写的类即使不写继承关系,那么也会继承Object
equals和==
判断左右两端的数据是否一致
字符串的判断一定要用equals
== 判断内存地址
toString方法
默认的toString是Object的方法 (包名+类名+@内存地址)
直接调用bean文件的toString方法 目录会以默认的地址 所以要在子类里重写toString方法
instanceof
可以判断两个对象是不是一个类型的
public class Test {
}
public class Demo extends Test{
public static void main(String[] args) {
Test test = new Demo();
if (test instanceof Demo){
System.out.println("y");
}else {
System.out.println("s");
}
// = y 是一个类型的
}
}
----------------------------
public class Test {
}
public class Demo extends Test{
public static void main(String[] args) {
Test test = new Test();
if (test instanceof Demo){
System.out.println("y");
}else {
System.out.println("s");
}
// = s 不是一个类型的
}
}
内存分析
- 堆 主要放对象
- 栈 局部变量,以及基本数据类型的变量
- 代码区:类和方法
- 数据区:常量池和静态变量
参数传递
public class Test {
String string;
public Test(String string) {
this.string = string;
}
private static void chaes(Test test1) {
test1.string="1011";
}
}
public class Demo {
public static void chae(Test test){
test = new Test("456");
}
public static void main(String[] args) {
Test test = new Test("123");
chae(test);
System.out.println(test.toString()); // = 123
Test test1 = new Test("789");
chaes(test1);
System.out.println(test1.string); // = 1011
System.out.println(test1.toString()); // = 1011
}
}
异常
要捕多个异常要从小到大
快捷键生成异常 选中代码 Ctrl + Alt + T
Throwable
最大得到异常要写在最后面
Error
VirtualMachineError
AWTError
Exception
IOException
RuntimeException
常用关键字:
try //尝试着去处理可能会出现异常的东西
catch //捕获异常
finally //无论有没有异常都会去运行
throw //抛出异常
throws //方法抛出异常
public static void main(String[] args) {
int a =1;
int b = 0;
try {
System.out.println(a/b);
}catch (ArithmeticException e){
e.printStackTrace(); //打印错误信息
System.out.println("程序出现异常");
}finally {
System.out.println("无论有没有异常都执行");
}
}
主动抛出异常
public class Demo {
public static void main(String[] args) {
try {
new Demo().test(1,0);
} catch (ArithmeticException e) {
e.printStackTrace();
}
System.out.println("ass"); //异常后程序还会执行
}
private void test(int a,int b) throws ArithmeticException{
if (b==0){ //throw主动抛出异常
throw new ArithmeticException();
}
System.out.println(a/b);
}
}
自定义异常
----MyException 新建自定义异常类继承想自定义的异常
public class MyException extends Exception{
private int detail;
public MyException(int a){ //新建异常值将错误的值打出来
this.detail = a;
}
@Override
public String toString() { //创建toString方法
return "MyException{" +
"detail=" + detail +
'}';
}
}
public class Demo {
static void demo(int a)throws MyException{
System.out.println("传递的参数为:"+a);
if (a>10){
throw new MyException(a); //大于10就会抛出
}
System.out.println("OK");
}
public static void main(String[] args) {
try {
demo(11); //11大于10 所以抛出异常
} catch (MyException e) {
System.out.println(e); //打印自定义异常 异常走捕获的内容
}
}
}
Math数学类
System.out.println(Math.abs(-12)); // = 12 绝对值属性
System.out.println(Math.pow(3,3)); // = 27 3的3次幂
System.out.println(Math.round(4.5)); // = 5 四舍五入
System.out.println(Math.sqrt(81)); // = 9 平方根
System.out.println(Math.max(12,32)); // = 32 最大值
System.out.println(Math.min(12,32)); // = 12 最小值
时间
Date date = new Date();
System.out.println(date); //获取当前时间
---------老方法
System.out.println(date.getYear()+1900); //从1900年开始
System.out.println(date.getMonth()+1); //月份从0开始
System.out.println(date.getDate()); //日
System.out.println(date.getHours()); //小时
System.out.println(date.getMinutes()); //分
System.out.println(date.getSeconds()); //秒
----------新方法
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DATE,calendar.get(Calendar.DATE)-1); //可以通过这个方法减去多少天
System.out.println(calendar.get(Calendar.YEAR)); //获取当前年份
System.out.println(calendar.get(Calendar.MONTH)+1); //获取当前月份月份从0就开始
System.out.println(calendar.get(Calendar.DATE)); //获取当前日期
-----------把Data时间转成Calendar
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date); //将data时间给calendar
System.out.println(calendar.get(Calendar.YEAR)); //获取当前年份
System.out.println(calendar.get(Calendar.MONTH)+1); //获取当前月份月份从0就开始
System.out.println(calendar.get(Calendar.DATE)); //获取当前日期
格式化时间
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = simpleDateFormat.format(date);
System.out.println(s);
----------------------字符串转成时间--------------------
String s = "2021-4-29 13:12:21";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date date = simpleDateFormat.parse(s);
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
计算时间
String s1 = "2021-4-29 13:12:21"; //开始时间
String s2 = "2021-4-29 17:18:21"; //结束时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d1 = simpleDateFormat.parse(s1);
Date d2 = simpleDateFormat.parse(s2);
long long1 = d1.getTime();
long long2 = d2.getTime();
long sum = Math.abs(long1-long2); //计算成毫秒级别的误差求绝对值
long miao = sum/1000; //秒级别差
long fen = miao/60; //分级别
long x1 = fen/60;
long x2 = fen%60;
System.out.println(x1+"小时"+x2+"分钟");
字符串
charAt(0) //拿到第0个字符
concat(“a”); //字符串后后面加a 拼接字符串
contains(“a”); //字符串中是否包含a
startsWith(“guan”); //字符串是否以guan 开始
endsWith(“xin”); //字符串是否以xin结尾
equalsIgnoreCase //忽略大小写是否一致
equals //判断两个字符串是否一致
indexOf(“c”) //判断字符串所在的位置
length() //字符串的长度
replace //替换
split //切割
substring(2,4) //截取
charAtString s = "guan";
System.out.println(s.charAt(0)); // = g 拿到第0个字符
String s1 = s.concat("xin"); // s1= guanxin 拼接字符串
String s = "guan";
System.out.println(s.contains("a")); // = true 里面是否包含了a
String s = "guanxin";
System.out.println(s.startsWith("guan")); //字符串是否以guan开始
System.out.println(s.endsWith("xin")); //字符串是否以xin结尾
String s = "abc";
String s1 = "ABC";
System.out.println(s.equalsIgnoreCase(s1)); // =true 忽略大小写内容是否一致
System.out.println(s.equals(s1)); //判断两个字符是否一致
System.out.println(s.indexOf("c")); // = 2 判断所在位置
System.out.println(s.length()); // = 3 字符串的chan'd
System.out.println(s.replace("c","a")); // = aba 将c替换成a
String s = "哈哈_呵呵_吼吼";
String[] s1 = s.split("_");
System.out.println(s1[1]); //= 呵呵 第1个数组
String s = "今天天气不错";
System.out.println(s.substring(2,4)); // = 天气
StringBuffer 和 StringBuilder
StringBuffer和StringBuilder用法都是一样的
StringBuilder >StringBuffer // StringBuilder 速度更快
append //末尾添加字符串
insert //在第几位后加入的字符串
String s = stringBuilder.toString(); //转成字符串
StringBuilder stringBuilder = new StringBuilder("123");
System.out.println(stringBuilder); // = 123
stringBuilder.append("456");
System.out.println(stringBuilder); // = 123456
stringBuilder.insert(3,"789");
System.out.println(stringBuilder); //123789456
字符串加法运算
String s = "12+12+31+32+52";
s = s.replace(" ",""); //去掉多余空格
String[] ss = s.split("\\+");
int sum = 0;
for (int i=0;i<ss.length;i++){
int a = Integer.parseInt(ss[i]);
sum += a;
}
System.out.println(sum);
侧手速
System.out.println("游戏马上开始");
Scanner scanner = new Scanner(System.in);
scanner.nextLine();
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND,calendar.get(Calendar.SECOND)+5); //往后延迟5秒
Date date = calendar.getTime();
long end = date.getTime(); //结束时间
int con = 0;
while (end - new Date().getTime() >= 0){
scanner.nextLine();
con++;
}
System.out.println("您一共按了"+con+"次");
double pin = con/5; // 5秒
DecimalFormat decimalFormat = new DecimalFormat(".00");
System.out.println("您的手速是:"+decimalFormat.format(pin)+"次/秒");
容器List,Map,Set.
- List 线性结构
- Set集合,非线性去除重复
- Map 映射 存储的时候以key:value的形式存储数据
List
用法一样 底层内存层面上有区别正常用感觉不到
ArrayList //查询效率比较高
LinkedList //删除和增加元素效率高
常用操作
add //添加
remove //删除
size //长度
get() //获取某个元素
contains //里面是否有这个数据
List<String> strings = Arrays.asList("1","2","3"); //新用法
strings.forEach(System.out::println);
Object obj = list.get(0); //list是一个object类型
String s = (String) obj; //强转成字符串
System.out.println(list.contains("1")); //查找list有没有 1
Set
- 不能有重复数据
- 不是按照存储的数据进行存放的
HashSet //无序的
TreeSet //默认进行排序 升序
操作
add(); //添加元素
remove(); //删除元素 remove(“wode”); //直接写删除的内容
contains //里面是否有这个数据
Set set = new HashSet();
set.add("123");
set.add("456");
set.add("789");
Iterator iterator = set.iterator();
while (iterator.hasNext()){
String s = (String) iterator.next();
System.out.println(s);
}
Map容器
如果出现重复的key之前的会被顶掉
HashMap //不排序
TreeMap //根据key来排序的只能排int类型 map.put(11,“wang”); map.put(12,“wen”);
操作
put(key,value) //存数据
remove(key) //删数据
size() //长度
keySet //打印所有key
get //通过key 查询value值
Map map = new HashMap();
map.put("1","s");
map.put("3","sff");
map.put("2","sd");
map.remove("1"); //删除 key 1
System.out.println(map); // = {2=sd, 3=sff}
System.out.println(map.keySet()); // = [2, 3] 打印所有的key
System.out.println(map.get("2")); //查询对应的value
迭代器
next //下一个
hasNext //是否还有下一个
List
List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
Iterator iterator = list.iterator(); //创建迭代器
while (iterator.hasNext()){ //判断是否有下一个
String s = (String) iterator.next();
System.out.println(s);
}
Set
Set set = new HashSet();
set.add("123");
set.add("456");
set.add("789");
Iterator iterator = set.iterator();
while (iterator.hasNext()){
String s = (String) iterator.next();
System.out.println(s);
}
Map
方案1
Map map = new HashMap();
map.put("xxx","123");
map.put("sss","456");
map.put("aaa","789");
Set set = map.keySet(); //拿到所有的key
Iterator iterator = set.iterator();
while (iterator.hasNext()){
String s = (String) iterator.next();
System.out.println(s);
System.out.println(map.get(s)); //通过key拿到所有value
}
方案2
Map map = new HashMap();
map.put("xxx","123");
map.put("sss","456");
map.put("aaa","789");
Set set = map.entrySet(); //set里面装的是entry
Iterator iterator = set.iterator();
while (iterator.hasNext()){
Map.Entry entry = (Map.Entry) iterator.next();
System.out.print(entry.getKey());
System.out.println(" "+entry.getValue());
}
泛型
Map<String,String> map = new HashMap<>();
map.put("1","123");
map.put("2","456");
map.put("3","789");
String s = map.get("1");
System.out.println(s); //= 123
Flie类
多线程
基础
Thread
线程开启不一定立即执行,由cpu调度
- 子类继承Thread
- 重写run()方法
- 写入线程体
- 去主线程调创建线程对象,调用start()方法启动线程
- 启动:子类对象.start();
public class Test extends Thread{
@Override
public void run() {
//run方法线程体
System.out.println("子线程方法");
}
public static void main(String[] args) {
//main方法 主线程
Test test = new Test();
test.start(); //使用start方法调用主线程和子线程同时运行
}
}
Runnable
实现接口Runnable具有多线程能力
启动线程:传入目标对象+Thread对象.start();
public class Test implements Runnable {
@Override
public void run() {
System.out.println("子线程方法");
// System.out.println(""+Thread.currentThread().getName()); //线程的名字 通过getname获取
}
public static void main(String[] args) {
Test test = new Test();
new Thread(test).start();
// new Thread(test,"我").start(); //可以给线程起名字
}
}
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();
Callable
callable和Runnable的区别是callable可以有返回值
线程停止
public class Test implements Runnable{
private boolean loop = true;
@Override
public void run() {
int i = 0;
while (loop){
i ++;
System.out.println("run···"+i);
}
}
public void stop(){
this.loop = false;
}
public static void main(String[] args) {
Test test = new Test();
new Thread(test).start();
try {
Thread.sleep(1000);
test.stop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
时间倒计时
public static void main(String[] args) throws InterruptedException {
Date date = new Date(System.currentTimeMillis());
while (true){
System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
date = new Date(System.currentTimeMillis());
Thread.sleep(1000);
}
}
礼让
Thread.yield(); //礼让
插队
public class Test implements Runnable{
@Override
public void run() {
for (int i=0;i<1000;i++){
System.out.println("vip"+i);
}
}
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
Thread thread = new Thread(test);
//
for (int i = 0; i < 300; i++) {
if (i==200){
thread.start(); //启动线程
thread.join(); //强制线程执行完再执行主线程
}
System.out.println("main"+i);
}
}
}
查看线程状态
线程只能启动一次
NEW //尚未启动的线程处于此状态
RUNNABLE //执行的线程
BLOCKED //阻塞等待监视器锁定的线程处于此状态
WAITING //正在等待另一个线程执行特定动作的线程处于此状态
TIMED WAITING //正在等待另一个线程执行动作达到的线程处于此状态
TERMINATED //已退出的线程
Thread.State state = thread.getState();
System.out.println(state); // = New 创建线程未启动
thread.start(); //启动线程
state = thread.getState(); //获取线程状态
System.out.println(state); // = RUNNABLE 线程启动
state = thread.getState(); //获取线程状态
System.out.println(state); // = TIMED_WAITING 线程正在运行
线程的优先级
线程优先级数字越大越高
setPriority
主线程默认 5
public class Test{
public static void main(String[] args) {
MyPriority myPriority = new MyPriority();
Thread t1 = new Thread(myPriority);
Thread t2 = new Thread(myPriority);
Thread t3 = new Thread(myPriority);
Thread t4 = new Thread(myPriority);
Thread t5 = new Thread(myPriority);
Thread t6 = new Thread(myPriority);
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY); //最大 = 10
t4.start();
t5.setPriority(9);
t5.start();
t6.setPriority(1);
t6.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
//getPriority 线程的优先级
System.out.println(Thread.currentThread().getName()+"---->"+Thread.currentThread().getPriority());
}
}
Lamda表达式
interface Ilove{ //实现接口
void love(int a);
}
class Love implements Ilove { //实现他的类
@Override
public void love(int a) {
System.out.println("I love you "+a);
}
}
public class Test {
public static void main(String[] args) {
Ilove ilove = new Love();
ilove.love(2);
}
}
简化方法1静态内部类
interface Ilove{
void love(int a);
}
public class Test {
static class Love implements Ilove { //静态内部类
@Override
public void love(int a) {
System.out.println("I love you "+a);
}
}
public static void main(String[] args) {
Ilove ilove = new Love();
ilove.love(2);
}
}
简化方法2局部内部类
interface Ilove{
void love(int a);
}
public class Test {
public static void main(String[] args) {
class Love implements Ilove { //将类名放到局部里
@Override
public void love(int a) {
System.out.println("I love you "+a);
}
}
Ilove ilove = new Love();
ilove.love(2);
}
}
实现方法3匿名内部类
interface Ilove{
void love(int a);
}
public class Test {
public static void main(String[] args) {
Ilove ilove = new Ilove() { //直接使用接口
@Override
public void love(int a) {
System.out.println("I love you "+a);
}
};
ilove.love(2);
}
}
实现方法4 Lambda简化
interface Ilove{
void love(int a);
}
public class Test {
public static void main(String[] args) {
Ilove ilove = (int a) ->{
System.out.println("I love you "+a);
};
ilove.love(520);
}
}
多线程进阶
进程:一个程序可以包含多个线程,只要包含一个
线程就是一个单独的资源类,没有任何附属操作 1.属性2.方法
java默认有2个线程,1、main线程 2、GC线程主要做垃圾回收
System.out.println(Runtime.getRuntime().availableProcessors()); //获取cpu的核数
线程的状态
public enum State {
//线程新生
NEW,
//运行
RUNNABLE,
//阻塞
BLOCKED,
//等待
WAITING,
//超时等待
TIMED_WAITING,
//终止
TERMINATED;
}
Synchronized锁
class Ticket {
private int number = 50;
//synchronized 锁 加上synchronized变得有秩序
public synchronized void sale(){
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余:"+number);
}
}
}
public static void main(String[] args) {
//多线程操作
Ticket ticket = new Ticket();
//使用Lamda表达式 (参数)->{ 代码 } 方法启动线程
new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"A").start();
new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"B").start();
new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"C").start();
}
Lock锁
Lock 接口
synchronized 和 Lock区别
- synchronized 内置java关键字,Lock是一个java类
- synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
- synchronized 会自动释放锁, Lock必须要手动释放锁,如果不释放锁,会被死锁
- synchronized 当线程1阻塞了,线程2会进行等待
- Lock 当线程1阻塞了,线程2不一定等待
- synchronized 可重入锁,不可以中断 非公平 ;Lock 可重入锁 不可以中断 可以判断锁 非公平(可以自己设置)
- synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码
Lock l = …; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }
ReentrantLock //可重入锁 (常用)
ReentrantReadWriteLock.ReadLock //读锁
ReentrantReadWriteLock.WriteLock //写锁
lock三部
new ReentrantLock();
lock.lock(); //加锁
lock.unlock(); //解锁
使用lock锁卖票
class Ticket {
private int number = 50;
Lock lock = new ReentrantLock(false);
public void sale(){
lock.lock(); //加锁
try {
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余:"+number);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock(); //解锁
}
}
}
public static void main(String[] args) {
//多线程操作
Ticket ticket = new Ticket();
new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"A").start();
new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"B").start();
new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"C").start();
}
线程等待 wait() 生产者消费者问题
初始方法
class Data {
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
while (number != 0){ //当不等于0的时候等待 -1 线程操作 //防止虚假唤醒用while 否则用if
this.wait();; //等待
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll(); //通知线程+1完成
}
//-1
public synchronized void decrement() throws InterruptedException {
while (number == 0){ //当等于0的时候等待 +1 线程操作 //防止虚假唤醒用while 否则用if
this.wait(); //如果=0就等待
}
number --;
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll(); //通知线程 -1 完成
}
}
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{for (int i=0;i<10;i++){
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}},"A").start();
new Thread(()->{for (int i=0;i<10;i++){
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}},"B").start();
}
Lock锁
condition.await();
condition.signalAll();
class Data {
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() throws InterruptedException{
lock.lock();
try {
while (number != 0){
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
condition.signalAll(); //通知其他线程 +1 完毕
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock(); //释放锁
}
}
// -1
public void decrement() throws InterruptedException{
lock.lock();
try {
while (number==0){
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
condition.signalAll(); //通知其他线程 -1 完毕
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock(); //释放锁
}
}
}
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{for (int i=0;i<10;i++){
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}},"A").start();
new Thread(()->{for (int i=0;i<10;i++){
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}},"B").start();
new Thread(()->{for (int i=0;i<10;i++){
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}},"C").start();
new Thread(()->{for (int i=0;i<10;i++){
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}},"D").start();
}
精准执行
按照顺序依次执行
class Data {
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
private int number = 1;
public void printA(){
lock.lock(); //打开锁
try {
while (number != 1){
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"=>AAA");
number = 2;
condition2.signal(); //只唤醒 condition2
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock(); //关闭锁
}
}
public void printB(){
lock.lock(); //打开锁
try {
while (number != 2){
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"=>AAA");
number = 3;
condition3.signal(); //只唤醒 condition3
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock(); //关闭锁
}
}
public void printC(){
lock.lock(); //打开锁
try {
while (number != 3){
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"=>AAA");
number = 1;
condition1.signal(); //只唤醒 condition1
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock(); //关闭锁
}
}
}
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i=0;i<10;i++){data.printA();}
},"A").start();
new Thread(()->{
for (int i=0;i<10;i++){data.printB();}
},"B").start();
new Thread(()->{
for (int i=0;i<10;i++){data.printC();}
},"C").start();
}
8锁
8锁,就是关于锁的8个问题
1、标准情况下,两个线程先打印 发短信还是 先打印 打电话? 1/发短信 2/打电话
1、sendSms延迟4秒,两个线程先打印 发短信还是 打电话? 1/发短信 2/打电话
synchronized 锁的对象是方法的调用者
public static void main(String[] args) {
Phone phone = new Phone();
// 锁的存在
new Thread(()->{ phone.sendSms(); },"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{ phone.call(); },"B").start();
}
class Phone{
// synchronized 锁的对象是方法的调用者!、
// 两个方法用的是同一个对象调用(同一个锁),谁先拿到锁谁执行!
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);// 抱着锁睡眠
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
// = 4秒后执行 发短信,后执行打电话
普通方法没有锁!不是同步方法,就不受锁的影响,正常执行
增加了一个普通方法后!先执行发短信还是Hello?// 普通方法
两个对象,两个同步方法, 发短信还是 打电话? // 打电话
public class Test04 {
public static void main(String[] args) {
// 两个对象,两个调用者,两把锁!
Phone2 phone1 = new Phone2();
Phone2 phone2 = new Phone2();
//锁的存在
new Thread(()->{ phone1.sendSms(); },"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{ phone2.call(); },"B").start();
new Thread(()->{ phone2.hello(); },"C").start();
}
}
class Phone2{
public synchronized void sendSms(){ // synchronized 锁的对象是方法的调用者!
try {
TimeUnit.SECONDS.sleep(4); //延迟4秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
public void hello(){ // 这里没有锁!不是同步方法,不受锁的影响
System.out.println("hello");
}
}
// = 先执行打电话,接着执行hello,4秒执行发短信
static静态的同步方法,锁的是Class
增加两个静态的同步方法,只有一个对象,先打印 发短信?打电话?
两个对象!增加两个静态的同步方法, 先打印 发短信?打电话?
public class Test04 {
public static void main(String[] args) throws InterruptedException {
// 两个对象的Class类模板只有一个,static,锁的是Class
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
//锁的存在
new Thread(()->{ phone1.sendSms(); },"A").start();
// 捕获
TimeUnit.SECONDS.sleep(1);
new Thread(()->{ phone2.call(); },"B").start();
}
}
// Phone3唯一的一个 Class 对象
class Phone3{
// synchronized 锁的对象是方法的调用者!
// static 静态方法
// 类一加载就有了!锁的是Class
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
// 先执行发短信,后执行打电话
1个静态的同步方法,1个普通的同步方法 ,一个对象,先打印 发短信?打电话?
1个静态的同步方法,1个普通的同步方法 ,两个对象,先打印 发短信?打电话?
public class Test04 {
public static void main(String[] args) {
// 两个对象的Class类模板只有一个,static,锁的是Class
Phone4 phone1 = new Phone4();
Phone4 phone2 = new Phone4();
//锁的存在
new Thread(()->{ phone1.sendSms(); },"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{ phone2.call(); },"B").start();
}
}
// Phone3唯一的一个 Class 对象
class Phone4{
// 静态的同步方法 锁的是 Class 类模板
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
// 普通的同步方法 锁的调用者(对象),二者锁的对象不同,所以不需要等待
public synchronized void call(){
System.out.println("打电话");
}
}
// 7/8 两种情况下,都是先执行打电话,后执行发短信,因为二者锁的对象不同,
// 静态同步方法锁的是Class类模板,普通同步方法锁的是实例化的对象,
// 所以不用等待前者解锁后 后者才能执行,而是两者并行执行,因为发短信休眠4s
// 所以打电话先执行。
S-Callable
Callable接口类似于Runnable
不同于:
- 可以有返回值
- 可以抛出异常
- 方法不同 run(),call();
public class Test04 {
public static void main(String[] args) throws Exception {
MyThread myThread = new MyThread();
FutureTask futureTask = new FutureTask(myThread); //适配类
new Thread(futureTask,"A").start(); //启动线程 调用方法
System.out.println(futureTask.get()); //获取返回值 = Callable
}
}
class MyThread implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("call");
return "Callable";
}
}
常用辅助类
CountDownLatch //加法计数
CyclicBarrier //减法计数
Semaphore //信号量
CountDownLatch
countDownLatch.countDown(); // 数量-1
countDownLatch.await(); // 等待计数器归零,然后再向下执行
每次有线程调用 countDown() 数量-1,假设计数器变为0,countDownLatch.await() 就会被唤醒,继续执行!
public class Test04 {
public static void main(String[] args) throws InterruptedException {
// 总数是6,必须要执行任务的时候,再使用!
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()
+" Go out");
countDownLatch.countDown(); // 数量-1
},String.valueOf(i)).start();
}
countDownLatch.await(); // 等待计数器归零,然后再向下执行
System.out.println("Close Door");
}
}
CyclicBarrier
public class Test04 {
public static void main(String[] args) {
/*
* 集齐7颗龙珠召唤神龙
*/
// 召唤龙珠的线程
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("召唤神龙成功!");
});
for (int i = 1; i <=7 ; i++) {
final int temp = i;
// lambda能操作到 i 吗
new Thread(()->{
System.out.println(Thread.currentThread().getName()
+"收集"+temp+"个龙珠");
try {
cyclicBarrier.await(); // 等待
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
Semaphore 信号量
semaphore.acquire(); //获得,假设如果已经满了,等待,等待被释放为止!
semaphore.release(); //释放,会将当前的信号量释放 + 1,然后唤醒等待的线程!
public class Test04 {
public static void main(String[] args) {
//线程数量:停车位
Semaphore semaphore = new Semaphore(3); //控制最大的线程
for (int i = 1; i <= 6; i++) {
new Thread(()->{
try {
semaphore.acquire(); //获得车位
System.out.println(Thread.currentThread().getName()+"青岛车位");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release(); //释放车位
}
},String.valueOf(i)).start();
}
}
}
读写锁 ReadWriteLock
public class Test04 {
public static void main(String[] args) {
//MyCache myCache = new MyCache();
MyCacheLock myCacheLock = new MyCacheLock();
for (int i = 1; i <= 5 ; i++) { // 写入
final int temp = i;
new Thread(()->{
myCacheLock.put(temp+"",temp+"");
},String.valueOf(i)).start();
}
for (int i = 1; i <= 5 ; i++) { // 读取
final int temp = i;
new Thread(()->{
myCacheLock.get(temp+"");
},String.valueOf(i)).start();
}
}
}
class MyCacheLock{ //加锁
private volatile Map<String,Object> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); // 读写锁: 更加细粒度的控制
// 存,写入的时候,只希望同时只有一个线程写
public void put(String key,Object value){
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入OK");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
// 取,读,所有人都可以读!
public void get(String key){
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"读取"+key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取OK");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
}
class MyCache{ //不加锁
private volatile Map<String,Object> map = new HashMap<>();
// 存,写
public void put(String key,Object value){
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入OK");
}
// 取,读
public void get(String key){
System.out.println(Thread.currentThread().getName()+"读取"+key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取OK");
}
}
!!!!!!阻塞队列
https://www.kuangstudy.com/bbs/1374937897278402561
https://www.kuangstudy.com/bbs/1374936485165297666
集合不安全
List
//并发下ArrayList 是不安全的 多线程下会报并发性异常 ConcurrentModificationException
public static void main(String[] args) {
// 并发下 ArrayList 不安全的吗,Synchronized;
/*
* 解决方案;
* 方案1、List<String> list = new Vector<>();
* 方案2、List<String> list =
* Collections.synchronizedList(new ArrayList<>());
* 方案3、List<String> list = new CopyOnWriteArrayList<>();
*/
/* CopyOnWrite 写入时复制 COW 计算机程序设计领域的一种优化策略;
* 多个线程调用的时候,list,读取的时候,固定的,写入(覆盖)
* 在写入的时候避免覆盖,造成数据问题!
* 读写分离
* CopyOnWriteArrayList 比 Vector Nb 在哪里?
*/
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 1; i <= 10; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
set
HashSet 的底层就是一个HashMap
Set set = new HashSet<>(); //不安全
Set set = Collections.synchronizedSet(new HashSet<>()); //安全
public static void main(String[] args) {
Set<String> set = new CopyOnWriteArraySet<>();//安全
for (int i = 1; i <=30 ; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
Map
map 是这样用的吗? 不是,工作中不用 HashMap
默认等价于什么? new HashMap<>(16,0.75);
Map<String, String> map = new HashMap<>();
扩展:研究ConcurrentHashMap的原理
public static void main(String[] args) {
Map<String,String> map = new ConcurrentHashMap<>();
for (int i = 0; i < 30; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}