java常见编程练习hw二(中等难度)

1. 进制转换

写出一个程序,接受一个十六进制的数,输出该数值的十进制表示。

[推荐、简单]思路:java内置 decode方法,将 String 解码为 Integer

直接调用Java的decode方法.
该方法的作用是将 String 解码为 Integer。接受十进制、十六进制和八进制数字。

根据要解码的 String(mn)的形式转成不同进制的数字。 mn由三部分组成:符号、基数说明符和字符序列。 -0X123中-是符号位,0X是基数说明符(0表示八进制,0x,0X,#表示十六进制,什么都不写则表示十进制),123是数字字符序列。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        
       Scanner sc=new Scanner(System.in);
        while (sc.hasNext()){
            String str=sc.next();
            System.out.println(Integer.decode(str));
        }
        
        
    }
}

【不推荐】思路2,自己计算

16进制 --> 10进制 思路: 比如:0x209

  1. 去掉 “ox”就剩下 209 (三位数:个-9、十-0、百-2)
  2. 10进制数 = 2 × 16^2 + 0 × 16^1 + 9 × 16^0 = 521

2. 质数因子

题目描述
功能:输入一个正整数,按照从小到大的顺序输出它的所有质因子(重复的也要列举)(如180的质因子为2 2 3 3 5 )

最后一个数后面也要有空格

输入描述:
输入一个long型整数

输出描述:
按照从小到大的顺序输出它的所有质数的因子,以空格隔开。最后一个数后面也要有空格。

思路1: 设定i=2,i一直递增,当N除以i余数为0的时候,N设定为N/i

这道题,需要一些数学基础。

质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。

质因子牵涉到两个概念:因子和质数;
因子,又叫“因数”或“约数”,如果整数a能被整数b整除,那就有一个整数q,使得 a=bq,则b和q都称为a的一个因子.15=3乘以5,所以3和5都是15的因子;8=2乘以4,那么2和4 就是8的因子。 质数,又叫“素数”,在大于1的自然数中,仅有1和本身为自己的因子的数叫素数。7 只有1、7这两个因子,所以是素数。8有1、2、4、8四个因子,除了1、8,还有2和4,所以就不是素数.

分解质因数的方法是先用一个合数的最小质因数去除这个合数,得出的数若是一个质数,就写成这个合数相乘形式;若是一个合数就继续按原来的方法,直至最后是一个质数 。

常规思路每一次遍历一遍2到N的全部的整数,找到一个质数因子a,然后将N设置为N/a,直到N等于1,但是这种方法其实就是暴力搜索,时间效率并不好。

其实有一种更好的方法,就是设定i=2,i一直递增,当N除以i余数为0的时候,N设定为N/i,否则i++,直到i>N,这样找到的所有N除以i余数为0的i就是N的所有的质数因子。

这样为什么可行呢?

我们假设从2开始,找到的第一个N除以i余数为0的i为a1,首先a1一定是质数,因为假如a1是合数的话在2和a1之间一定存在其他N可以整除的质数,但是i是从2开始找到的第一个可以整除的数,因此i只能是质数,也就是说i是N最小的质因子。

然后从a1继续往后找,找到第二个N可以整除的数a2,a2不可能是合数,因为假如a2是和数的话,2到a1,或者是a1到a2之间一定存在没有分解的质数,而这是不可能的,所以a2一定是质数,且是N第二大的质因子,进行将N设定为N/a2。

继续以上操作,当找到最后一个质因子的时候,N==i,这个时候算法结束,至此,N的所有质因子都找到了。

import java.util.Scanner;

public class Main{

    public static void handler(int num) {
        while(num != 1) {
            for(int i = 2; i <= num; ++i) {
                if( num % i == 0) {
                    System.out.print( i + " ");
                    num = num / i;
                    break;
                }
            }    
        }
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()) {
            handler(sc.nextInt());
        }

    }
}

3. 合并表记录

题目描述
数据表记录包含表索引和数值(int范围的整数),请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。

输入描述:
先输入键值对的个数
然后输入成对的index和value值,以空格隔开

输出描述:
输出合并后的键值对(多行)

示例1

输入:
4
0 1
0 2
1 2
3 4

输出:
0 3
1 2
3 4

思路:使用有序的TreeMap

此题如果直接使用有序的TreeMap就不需要这样折腾:
1.map的key值唯一性,故就不在需要set集合来去重
2.使用map后利用key的唯一性,把序列号相同的数据直接加在一起,代码会很简洁

import java.util.*;
public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int num = sc.nextInt();
		TreeMap<Integer,Integer> treeMap = new TreeMap<>();
		while (num>0){
			int key = sc.nextInt();
			int value = sc.nextInt();
			if (!treeMap.containsKey(key)){
				treeMap.put(key,value);
			}else{
				treeMap.put(key,Math.addExact(treeMap.get(key),value));
			}
			num--;
		}
		for (Integer key : treeMap.keySet()) {
			System.out.println(key+" "+treeMap.get(key));
		}
	}
}

4. 提取不重复的整数

1,题目描述:输入一个int型整数,按照从右往左的阅读顺序,返回一个不含重复数字的新的整数

2,输入描述:输入一个int型整数

3,输出描述:按照从右到左的阅读顺序,返回一个不含重复数字的新的整数

4,输入例子:8976673

5,输出例子:37689

思路1 创建一个长度为10的数组

使用java写一个程序:输入一个int型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。
参考URL: https://blog.csdn.net/weixin_45710839/article/details/105695392

int num = numStr.charAt(i) - 48;是什么意思?
把char型数字转换成的int型数字,因为它们的ASCII码值恰好相差48
因此把char型数字减去48得到int型数字,例如’4’被转换成4。

该思路比较好,推荐掌握。

import java.util.Scanner;

//输入一个int型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。
public class Demo6 {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        //因为要返回一个不含重复数字的新整数,这里我们要对已经有的数做出表示,且最多只有10个数字
        //这里我们创建一个长度为10的数组
        int[] arr = new int[10];
        for (int i = s.length() - 1; i >=0; i--) {
            if (arr[s.charAt(i) - 48] == 0) {
                System.out.print(s.charAt(i)-48);
                arr[s.charAt(i) - 48]++;
            }
        }

    }

}


5. 字符个数统计

题目描述
编写一个函数,计算字符串中含有的不同字符的个数。字符在ACSII码范围内(0~127),换行表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次
例如,对于字符串abaca而言,有a、b、c三种不同的字符,因此输出3。
输入描述:
输入一行没有空格的字符串。

输出描述:
输出范围在(0~127)字符的个数。

例1
输入
abc
输出
3

HashSet

涉及到去重的时候,又是单列表,首先想到HashSet,唯一的难点是判断字符的ASCII码在(0-127)这个范围内;其实只要把字符强转成整型,就是其对应的ASCII码了。这种情况下只要判断 该值是否在0-127内就可以了。

char型与int的相互转化
char与int的相互转化,联想ASCII码,字符‘0’对应的值为48,所以不能直接加减‘ ’

如何把 char ‘9’ 转为 int 9, 大家应该知道,不能直接转化,那样得到是‘9’的Ascii

  1. char转int
    char ch=‘9’;
    int ch_int=ch-‘0’;//此时ch_int=9

  2. int转char
    int i=9;
    char i_ch=i+‘0’;//此时i_ch=‘9’

总结:经过测试, 默认会自动转换成字符对应的ascii码,char 直接复制给int,也可以自动转换。如: int i = ch;

根据业务需要,看自己属于哪种情况。本例中要的就是字符的本身的acsii吗 在0-127之间,所以直接编码为 int i =c;

import java.util.*;
public class Main {
    public static void main(String[] args){
        Scanner sc =new Scanner(System.in);
        HashSet<Integer> set = new HashSet<>();
        //HashSet<Character> set = new HashSet<>();
        //while(sc.hasNext("")){
        String s = sc.nextLine();
        char[] charArray = s.toCharArray();
        for(char c : charArray){
            int i =c;
            if(i>=0 && i<=127){
                set.add(i);
            }
        }
        System.out.println(set.size());
        //}
    }
}

6. 字符串排序

题目描述
给定n个字符串,请对n个字符串按照字典序排列。
输入描述:
输入第一行为一个正整数n(1≤n≤1000),下面n行为n个字符串(字符串长度≤100),字符串中只含有大小写字母。
输出描述:
数据输出n行,输出结果为按照字典序排列的字符串。
示例1
输入
9
cap
to
cat
card
two
too
up
boat
boot
输出
boat
boot
cap
card
cat
to
too
two
up

思路:利用java 的 Arrays.sort 排序数组即可

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);

        while(sc.hasNext()){
            int n = sc.nextInt();
            String[] arr = new String[n];
            for(int i=0;i<n;i++){
                String str = sc.next();
                arr[i] = str;
            }
            Arrays.sort(arr);
            
           for(int i=0;i<arr.length;i++){
                System.out.println(arr[i]);
            }
        }

7. 购物单 (TODO 难一点)

题目描述
王强今天很开心,公司发给N元的年终奖。王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

主件附件
电脑打印机,扫描仪
书柜图书
书桌台灯,文具
工作椅

如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。王强想买的东西很多,为了不超出预算,他把每件物品规定了一个重要度,分为 5 等:用整数 1 ~ 5 表示,第 5 等最重要。他还从因特网上查到了每件物品的价格(都是 10 元的整数倍)。他希望在不超过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第 j 件物品的价格为 v[j] ,重要度为 w[j] ,共选中了 k 件物品,编号依次为 j 1 , j 2 ,……, j k ,则所求的总和为:

v[j 1 ]*w[j 1 ]+v[j 2 ]*w[j 2 ]+ … +v[j k ]*w[j k ] 。(其中 * 为乘号)

请你帮助王强设计一个满足要求的购物单。

输入描述:

输入的第 1 行,为两个正整数,用一个空格隔开:N m

(其中 N ( <32000 )表示总钱数, m ( <60 )为希望购买物品的个数。)

从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v p q

(其中 v 表示该物品的价格( v<10000 ), p 表示该物品的重要度( 1 ~ 5 ), q 表示该物品是主件还是附件。如果 q=0 ,表示该物品为主件,如果 q>0 ,表示该物品为附件, q 是所属主件的编号)

输出描述:

输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值( <200000 )。

输入例子:

1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0

输出例子:

2200

思路1:给定购物单,逐级增加金额和件数,直到达到购物单上限止(商品件数或者总金额)

参考URL: https://my.oschina.net/u/2822116/blog/822770

思路:给定购物单,逐级增加金额和件数,直到达到购物单上限止(商品件数或者总金额);逐级计算出所对应的最大乘积值,并在此过程中,比较出到此级为止的乘积最大值

8. 简单密码破解

题目描述
密码是我们生活中非常重要的东东,我们的那么一点不能说的秘密就全靠它了。哇哈哈. 接下来渊子要在密码之上再加一套密码,虽然简单但也安全。

假设渊子原来一个BBS上的密码为zvbo9441987,为了方便记忆,他通过一种算法把这个密码变换成YUANzhi1987,这个密码是他的名字和出生年份,怎么忘都忘不了,而且可以明目张胆地放在显眼的地方而不被别人知道真正的密码。

他是这么变换的,大家都知道手机上的字母: 1–1, abc–2, def–3, ghi–4, jkl–5, mno-- 6, pqrs–7, tuv–8 wxyz–9, 0–0,就这么简单,把密码中出现的小写字母都变成对应的数字,数字和其他的符号都不做变换,

声明:密码中没有空格,而密码中出现的大写字母则变成小写之后往后移一位,如:X,先变成小写,再往后移一位,不就是y了嘛,简单吧。记住,z往后移是a哦。

输入描述:
输入包括多个测试数据。输入是一个明文,密码长度不超过100个字符,输入直到文件结尾

输出描述:
输出渊子真正的密文

输入例子:
YUANzhi1987

输出例子:
zvbo9441987

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String pwd = sc.next();
            System.out.println(crackpwd(pwd));
        }
    }

    public static String crackpwd(String s) {
        StringBuffer sb = new StringBuffer(s);
        for (int i = 0; i < sb.length(); i++) {
            if ('A' <= sb.charAt(i) && sb.charAt(i) <= 'Z') {
                if (sb.charAt(i) == 'Z') {
                    sb.setCharAt(i, 'a');
                } else
                    sb.setCharAt(i,
                            Character.toLowerCase((char) (sb.charAt(i) + 1)));
            } else if ('a' <= sb.charAt(i) && sb.charAt(i) <= 'z') {
                if (String.valueOf(sb.charAt(i)).matches("[abc]")) {
                    sb.setCharAt(i, '2');
                }
                if (String.valueOf(sb.charAt(i)).matches("[def]")) {
                    sb.setCharAt(i, '3');
                }
                if (String.valueOf(sb.charAt(i)).matches("[ghi]")) {
                    sb.setCharAt(i, '4');
                }
                if (String.valueOf(sb.charAt(i)).matches("[jkl]")) {
                    sb.setCharAt(i, '5');
                }
                if (String.valueOf(sb.charAt(i)).matches("[mno]")) {
                    sb.setCharAt(i, '6');
                }
                if (String.valueOf(sb.charAt(i)).matches("[pqrs]")) {
                    sb.setCharAt(i, '7');
                }
                if (String.valueOf(sb.charAt(i)).matches("[tuv]")) {
                    sb.setCharAt(i, '8');
                }
                if (String.valueOf(sb.charAt(i)).matches("[wxyz]")) {
                    sb.setCharAt(i, '9');
                }
            }
        }
        return sb.toString();
    }
}

推荐练习,掌握 cahrAt,字符转换等常见操作。

9. 坐标移动

题目描述
开发一个坐标计算工具, A表示向左移动,D表示向右移动,W表示向上移动,S表示向下移动。从(0,0)点开始移动,从输入字符串里面读取一些坐标,并将最终输入结果输出到输出文件里面。

输入:

合法坐标为A(或者D或者W或者S) + 数字(两位以内)

坐标之间以;分隔。

非法坐标点需要进行丢弃。如AA10; A1A; % ; YAD; 等。

下面是一个简单的例子 如:

A10;S20;W10;D30;X;A1A;B10A11;;A10;

处理过程:

起点(0,0)

  • A10 = (-10,0)

  • S20 = (-10,-20)

  • W10 = (-10,-10)

  • D30 = (20,-10)

  • x = 无效

  • A1A = 无效

  • B10A11 = 无效

  • 一个空 不影响

  • A10 = (10,-10)

结果 (10, -10)

注意请处理多组输入输出

输入描述:
一行字符串

输出描述:
最终坐标,以逗号分隔

示例1
输入
复制
A10;S20;W10;D30;X;A1A;B10A11;;A10;
输出
复制
10,-10

思路:根据 ‘;’ 分割指令,然后判断是不是合法的,合法的指令长度 是 2或者3,同时从下标1开始的字符必须是 数字 0-9.

思路:根据 ‘;’ 分割指令,然后判断是不是合法的,合法的指令长度 是 2或者3,同时从下标1开始的字符必须是 数字 0-9.

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext()){
           String s = sc.nextLine();
            String[] a  = s.split(";");
            int x=0;
            int y=0;
            for(int i = 0;i<a.length;i++){
                if(a[i].charAt(0)=='A'&&a[i].substring(1).matches("[0-9]{1,2}")){
                     x-= Integer.parseInt(a[i].substring(1));
                }
                if(a[i].charAt(0)=='S'&&a[i].substring(1).matches("[0-9]{1,2}")){
                    y-=Integer.parseInt(a[i].substring(1));
                }
                if(a[i].charAt(0)=='W'&&a[i].substring(1).matches("[0-9]{1,2}")){
                    y+=Integer.parseInt(a[i].substring(1));
                }
                if(a[i].charAt(0)=='D'&&a[i].substring(1).matches("[0-9]{1,2}")){
                    x+=Integer.parseInt(a[i].substring(1));
                }
            }
            System.out.println(x+","+y);
    }
  }
}

总结:根据提意,根据正则判断输入坐标合法性。

10. 求解立方根

题目描述
计算一个数字的立方根,不使用库函数。
保留一位小数。

输入描述:
待求解参数,为double类型(一个实数)

输出描述:
输入参数的立方根。保留一位小数。

示例1
输入
216
输出
6.0

总结:TODO掌握!

思路1:采用牛顿迭代法

Java实现牛顿迭代法求解平方根、立方根
参考URL: https://www.cnblogs.com/ryelqy/p/10842794.html

思路:不使用Math.pow()方法,采用牛顿迭代法,这里可能需要理解一下牛顿迭代过程。

需要掌握数学 牛顿迭代法。
牛顿迭代法。设f(x)=x 3-y, 求f(x)=0时的解x,即为y的立方根。
根据牛顿迭代思想,x n+1=x n-f(x n)/f’(x n)即x=x-(x 3-y)/(3x 2)=(2x+y/x/x)/3;

	// 牛顿迭代法
	public static double getLiFangGen(double num) {
        if (num == 0) {
            return num;
        }
    
        double num1,num2;
        num1 = num;
        num2 = (2*num1/3)+(num/(num1*num1*3));//利用牛顿迭代法求解  
        while(Math.abs(num2-num1)>0.000001){  
            num1=num2;  
            num2=(2*num1/3)+(num/(num1*num1*3));  
        }  
        DecimalFormat df = new DecimalFormat("#.0");
        return Double.parseDouble(df.format(num2));  
    }

	public static void main(String args[]){
        Scanner sc = new Scanner(System.in);
        double input = sc.nextDouble();
        System.out.println(getLiFangGen(input));  
    }

思路2:二分法

今天开始学Java 计算一个数字的立方根,不使用库函数
参考URL: https://www.it610.com/article/1292831736723480576.htm

11. 字符统计

题目描述
输入一个只包含小写英文字母和数字的字符串,按照不同字符统计个数由多到少输出统计结果,如果统计的个数相同,则按照ASCII码由小到大排序输出。
本题含有多组样例输入

输入描述:
一个只包含小写英文字母和数字的字符串。

输出描述:
一个字符串,为不同字母出现次数的降序表示。若出现次数相同,则按ASCII码的升序输出。

思路: 使用一个hash表(unordered_map)存储 <字符, 出现次数> 的键值对, 然后按出现次数count进行排序(C++算法库中的sort函数), 排序时注意当统计的个数相同时, 按照ASII码由小到大顺序输出.

解本题总共分三步

  1. 将字符串转换成字符数组。创建字符ascll码对应的整型数组,该数组长度必须大于128,字符的ascll码值就是该数组的下标,遍历字符数组,字符每出现一次对应ascll下标的整数就加一。
  2. 找出该整型数组的最大值。
  3. 在整型数组中匹配max,找到则将该整数下标对应的字符加入可变字符序列,max自减直至max为零。(本题无需考虑字符个数相同的情况,因为字符ascll码对应的整型数组本来就是排好的)

字符对应ascll码值下标元素自增来统计数量,使用 (int) i 强转 char i 到对应ascii码。

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            System.out.println(count(sc.nextLine()));
        }

    }
    public static String count(String str) {
        char[] strArray = str.toCharArray();
        int[] chArray = new int[129];
        //字符对应ascll码值下标元素自增来统计数量
        for (char i : strArray){
            chArray[(int) i]++;
        }
        
        int max = 0;
        //找出字符数量最多的ascll码值
        for (int i = 0; i < chArray.length; i++){
            if (max < chArray[i]){
                max = chArray[i];
            }
        }

        StringBuilder sb = new StringBuilder();
        //按数量从大到小添加到可变字符序列sb
        while (max != 0) {
            for (int i = 0; i < chArray.length; i++){
                if (chArray[i] == max){
                    sb.append((char) i);
                }
            }
            max--;
        }
        return sb.toString();
    }

基础,必须掌握!

11. 扑克牌大小

题目描述
扑克牌游戏大家应该都比较熟悉了,一副牌由54张组成,含3~A、2各4张,小王1张,大王1张。牌面从小到大用如下字符和字符串表示(其中,小写joker表示小王,大写JOKER表示大王):
3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
输入两手牌,两手牌之间用"-“连接,每手牌的每张牌以空格分隔,”-"两边没有空格,如:4 4 4 4-joker JOKER。
请比较两手牌大小,输出较大的牌,如果不存在比较关系则输出ERROR。
基本规则:
(1)输入每手牌可能是个子、对子、顺子(连续5张)、三个、炸弹(四个)和对王中的一种,不存在其他情况,由输入保证两手牌都是合法的,顺子已经从小到大排列;
(2)除了炸弹和对王可以和所有牌比较之外,其他类型的牌只能跟相同类型的存在比较关系(如,对子跟对子比较,三个跟三个比较),不考虑拆牌情况(如:将对子拆分成个子);
(3)大小规则跟大家平时了解的常见规则相同,个子、对子、三个比较牌面大小;顺子比较最小牌大小;炸弹大于前面所有的牌,炸弹之间比较牌面大小;对王是最大的牌;

(4)输入的两手牌不会出现相等的情况。

思路1: split 分隔,根据牌面情况分类比较

扑克牌大小
参考URL: https://cloud.tencent.com/developer/article/1617249

不要被这个题吓到,灵活运用split 分隔比较即可,根据题干,比较的情况就那么几种。

import java.util.Scanner;

public class Main {
    static String resultline;

    public static int count(String str){
        return "345678910JQKA2jokerJOKER".indexOf(str);
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
            String str = in.nextLine();
            if ( str.contains("joker JOKER")){
                resultline = "joker JOKER";
            }else{
                String[] split = str.split("-");
                String[] left = split[0].split(" ");
                String[] right = split[1].split(" ");
                if ( left.length == 4 && right.length != 4){
                    resultline = split[0];
                }else if ( left.length != 4 && right.length == 4){
                    resultline = split[1];
                }else if (left.length == right.length){
                    if ( count(left[0]) > count(right[0])){
                        resultline = split[0];
                    }else{
                        resultline = split[1];
                    }
                }else{
                    resultline = "ERROR";
                }
            }
            System.out.print(resultline);
        }
        in.close();
    }

}

12. 多线程打印ABCD 【TODO】

题目描述:

  • 问题描述:有4个线程和1个公共的字符数组。
  • 线程1的功能就是向数组输出A,线程2的功能就是向字符输出B,线程3的功能就是向数组输出C,
  • 线程4的功能就是向数组输出D。要求按顺序向数组赋值ABCDABCDABCD,ABCD的个数由线程函数1的参数指定

示例1
输入
10
输出
ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD

思路:用Objcet类中的wait()方法和notify()方法

java实现多线程打印ABCD
参考URL: https://blog.csdn.net/qq_40976527/article/details/105193536

实现思路:
让A线程分配对象锁a,b。
让B线程分配对象锁b,c。
让C线程分配对象锁c,d。
让D线程分配对象锁d,a。
接下就是重点,我们会用Objcet类中的wait()方法和notify()方法。
wait():等待,如果线程执行了wait方法,那么该线程会进入等待的状态,等待状态下的线程必须要被其他线程调用notify()方法才能唤醒。wait()方法执行后,当前线程释放锁,其他线程可以竞争该锁。
notify()方法执行后,唤醒线程不会立刻释放锁,要等唤醒线程全部执行完毕后才释放对象锁。
我们要做的就是在A线程在执行打印“A”后,就唤醒B线程,然后让A线程进入等待。以此类推,B线程在执行打印“B”后,就唤醒C线程,然后让B线程进入等待。C线程在执行打印“C”后,就唤醒D线程,然后让C线程进入等待。D线程在执行打印“D”后,就唤醒A线程,然后让D线程进入等待。
这里有个问题我们在启动线程的时候为了确保A线程先打印,我们在初始化线程的时候在线程中增加了两个静态变量newIndex,runIndex。(静态变量的值是所有线程共享的)给线程分别制定相对应的id。id = newIndex++线程执行之后runIndex++。初始化A线程id为0,runIndex为0,B线程为1,runIndex为1,C线程为2,runIndex为2,D线程为3,runIndex为3,当id > runIndex 时说明这个线程是首次执行且还不应该到它执行打印,所以把它在外层synchronized的对象上休眠等待它上一个线程执行答应后唤醒它。
在判断此次打印不是最后一次后则让该线程进入等待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西京刀客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值