diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..554ea79 --- /dev/null +++ b/.gitignore @@ -0,0 +1,72 @@ +# Created by .ignore support plugin (hsz.mobi) +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +.idea/ +src/main/main.iml +src/test/test.iml \ No newline at end of file diff --git a/README.md b/README.md index ecd1f1f..88bb506 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,98 @@ # JavaTutorial内容说明 该Java教程是学习Java过程中对Java知识点进行梳理。每一个包中的代码都有一个ReadMe来说明该包代码的作用以及知识点。 +src包里面是Java的源码,test包里面是针对源码的测试 -![Alt text](images/JavaTutorial目录.jpg) +![Alt text](images/JavaTutorial目录.png) ## ThreadTutorial内容说明 在源码路径下`cn.byhieg.threadtutorial`中放置的是Java多线程的代码和测试例子,在每一个章的包下,都有一个ReadMe来说明该章的知识点。 + +在char01包里放置Java多线程基本知识的代码。内容如下: + +1. 如何使用多线程 +2. 如何得到多线程的一些信息 +3. 如何停止线程 +4. 如何暂停线程 +5. 线程的一些其他用法 + +在char02包里放置了Java对变量和对象并发访问的知识的代码。内容如下: + +1. 对于方法的同步处理 +2. 对于语句块的同步处理 +3. 对类加锁的同步处理 +4. 保证可见性的关键字——volatile + +在char03包里放置了Java线程间通信的知识的代码。内容如下: + +1. 等待/通知机制 +2. join方法的使用 + +在char04包里放置了Java中Lock类的知识的代码,内容如下: + +1. Lock类 +2. Lock类其他功能 +3. Condition类 +4. Condition类其他功能 +5. 读写锁 + +在char05包里放置了生产者/消费者的知识的代码,内容如下: + +1. 一对一 生产者/消费者 +2. 一对多 生产者/消费者 +3. 多对多 生产者/消费者 + +## ReflectionTutorial内容说明 +在源码路径下`cn.byhieg.reflectiontutorial`中放置的是Java反射的代码和测试例子,在每一个章的包下,都有一个ReadMe来说明该章的知识点。 +在包下面,不细分包,整个教程的讲解内容如下: +Java通过反射获取如下内容: + +- Class对象 +- 构造器 +- 变量 +- 方法 +- 私有变量与私有方法 +- 注解 +- 泛型 +- 数组 + +## CollectionTutorial内容说明 +在源码路径下`cn.byhieg.collectiontutorial`中放置的是Java集合类的代码和测试例子。在每一个包里面,都有一个ReadMe来说明该章的知识点。 +ListTutorial中的知识点有 + +- ArrayList的使用 +- 实现一个简单的ArrayList + +MapTutorial中的知识点有 + +- HashMap的使用 +- TreeMap的使用 +- LinkedHashMap的使用 + +## AnnotationTutorial内容说明 + +在源码路径下`cn.byhieg.annotationtutorial`中放置的是Java注解类的代码和测试例子。在每一个包里面,都有一个ReadMe来说明该章的知识点。 + + +## IOTutorial内容说明 + +在源码路径下`cn.byhieg.iotutorial`中放置的是Java io类的代码和测试例子。在每一个包里面,都有一个ReadMe来说明该章的知识点。 + +## DesignPattern内容说明 + +在源码路径下`cn.byhieg.designpatterntutorial`中放置的是Java 设计模式的代码和测试的例子。目前有 + +- 代理模式 +- 单例模式 +- builder模式 + +## algorithmtutorial内容说明 + +在源码路径下`cn.byhieg.algorithmtutorial`中放置的是Java实现的一些算法,内容如下: + +- 二叉搜索树 +- 二叉树的常见的算法 +- 查找算法, +- 图的算法(DFS,BFS,Dijkstra) +- 单链表的算法 +- 排序算法。 + diff --git "a/images/JavaTutorial\347\233\256\345\275\225.jpg" "b/images/JavaTutorial\347\233\256\345\275\225.jpg" deleted file mode 100644 index 65e5566..0000000 Binary files "a/images/JavaTutorial\347\233\256\345\275\225.jpg" and /dev/null differ diff --git "a/images/JavaTutorial\347\233\256\345\275\225.png" "b/images/JavaTutorial\347\233\256\345\275\225.png" new file mode 100644 index 0000000..f7c0041 Binary files /dev/null and "b/images/JavaTutorial\347\233\256\345\275\225.png" differ diff --git a/images/Thumbs.db b/images/Thumbs.db new file mode 100644 index 0000000..65a9b74 Binary files /dev/null and b/images/Thumbs.db differ diff --git a/javaturorial.iml b/javaturorial.iml new file mode 100644 index 0000000..4e3316b --- /dev/null +++ b/javaturorial.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 51d57e9..b88d83d 100644 --- a/pom.xml +++ b/pom.xml @@ -7,6 +7,18 @@ cn.byhieg javaturorial 0.1 + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + UTF-8 diff --git a/src/main/java/cn/byhieg/algorithmtutorial/BinarySearchTree.java b/src/main/java/cn/byhieg/algorithmtutorial/BinarySearchTree.java new file mode 100644 index 0000000..3aaffd5 --- /dev/null +++ b/src/main/java/cn/byhieg/algorithmtutorial/BinarySearchTree.java @@ -0,0 +1,349 @@ +package cn.byhieg.algorithmtutorial; + +/** + * Created by byhieg on 17/3/30. + * Mail to byhieg@gmail.com + */ + +import java.util.LinkedList; +import java.util.Queue; +import java.util.Stack; + +/** + * 该类是二叉搜索树 + * 该树在实现的时候,不考虑数组中有重复的数字。 + * 节点的左子节点的值都小于这个节点的值,节点的右子节点的值都大于等于这个节点的值 + */ +public class BinarySearchTree { + + private Node root; + + + public BinarySearchTree() { + + } + + + public BinarySearchTree(int[] nums) { + Node[] nodes = new Node[nums.length]; + for (int i = 0; i < nums.length; i++) { + nodes[i] = new Node(nums[i]); + insert(nodes[i]); + } + } + + /** + * 查找指定的元素 + * + * @param des + * @return + */ + public Node find(int des) { + if (root == null) { + System.out.println("树是空的"); + throw new RuntimeException(); + } + Node current = root; + while (current.data != des) { + if (current.data < des) { + current = current.right; + } else { + current = current.left; + } + if (current == null) return null; + } + return current; + } + + /** + * 对BST执行插入操作,采用非递归的形式 + * 保证插入后,左节点的值小于根节点的值,根节点的值小于右节点的值 + * + * @param node + * @return + */ + public boolean insert(Node node) { + if (root == null) { + root = node; + return true; + } + + if (find(node.data) != null) { + System.out.println("不允许插入相同data的数"); + throw new RuntimeException(); + } + + Node current = root; + while (current != null) { + if (current.data < node.data) { + if (current.right == null) { + current.right = node; + return true; + } + current = current.right; + } else { + if (current.left == null) { + current.left = node; + return true; + } + current = current.left; + } + } + return false; + + } + + /** + * 树的前序遍历,递归实现 + */ + public void preOrder(Node node) { + System.out.print(node.data + "-->"); + if (node.left != null) { + preOrder(node.left); + } + if (node.right != null) { + preOrder(node.right); + } + } + + /** + * 树的中序遍历,递归实现 + * 针对BST,该结果会从小到大输出树 + * + * @param node + */ + public void inOrder(Node node) { + if (node.left != null) { + inOrder(node.left); + } + System.out.print(node.data + "-->"); + if (node.right != null) { + inOrder(node.right); + } + } + + /** + * 树的后续遍历,递归实现 + */ + public void postOrder(Node node) { + if (node.left != null) { + postOrder(node.left); + } + if (node.right != null) { + postOrder(node.right); + } + System.out.print(node.data + "-->"); + } + + + /** + * 树的先续遍历,非递归实现 + * 1. 建立一个栈,现将头结点压入栈中。 + * 2. 现将每出栈一个节点,打印他的值,然后都要先加入他的右节点,在加入他的左节点。因为栈的后进先出的特性,才能让左边先出。 + * 3. 不断重复2,直到栈空 + */ + public void preOrder2(Node node) { + if (node != null) { + Stack stack = new Stack<>(); + stack.push(node); + while (!stack.isEmpty()) { + Node tmp = stack.pop(); + System.out.print(tmp.data + "-->"); + if (tmp.right != null) { + stack.push(tmp.right); + } + if (tmp.left != null) { + stack.push(tmp.left); + } + } + System.out.println("结束"); + + } + } + + /** + * 树的中序遍历,非递归实现 + * 1. 设定cur,初始化cur = root节点,不断遍历里cur.left,并将其压入栈中,直到null。 + * 2. 出栈一个节点,打印他的值,然后cur = node.right,并不断重复第二步 + * 3. 当栈为空,并且cur为空时,停止 + */ + public void inorder2(Node node) { + if (node != null) { + Stack stack = new Stack<>(); + Node cur = node; + while (!stack.isEmpty() || cur != null) { + if (cur == null) { + cur = stack.pop(); + System.out.print(cur.data + "-->"); + cur = cur.right; + } else { + stack.push(cur); + cur = cur.left; + } + } + System.out.println("结束"); + + } + } + + /** + * 树的后续遍历,非递归实现 + * 1. 树的先续遍历中,是栈存放顺序是根,右节点,左节点。 + * 2. 我们可以将其反过来,用栈存放是根,左节点,右节点。然后出栈的时候,将出栈的结果存放到另一个栈里。 + * 3. 第二栈里的顺序从上到下就是左节点,右节点,根的顺序。 + * + * @param node + */ + + public void postOrder2(Node node) { + if (node != null) { + Stack stack = new Stack<>(); + Stack result = new Stack<>(); + Node cur = node; + stack.push(cur); + while (!stack.isEmpty()) { + Node tmp = stack.pop(); + result.push(tmp); + if (tmp.left != null) { + stack.push(tmp.left); + } + if (tmp.right != null) { + stack.push(tmp.right); + } + } + + while (!result.isEmpty()) { + System.out.print(result.pop().data + "-->"); + } + System.out.println("结束"); + + } + } + + /** + * 树的层次遍历,类似于图的BFS + * @param root + */ + public void levelRead(Node root) { + if (root == null) return; + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + Node current = queue.poll(); + System.out.print(current.data + "-->"); + if (current.left != null) { + queue.offer(current.left); + } + if (current.right != null) { + queue.offer(current.right); + } + } + System.out.println("结束"); + + } + + + + + /** + * 得到树中最小的节点 + * + * @return + */ + public Node getMinNode() { + if (root == null) { + throw new RuntimeException("树为空"); + } + Node current = root; + while (current.left != null) { + current = current.left; + } + return current; + + } + + /** + * 得到树中最大的节点 + * + * @return + */ + public Node getMaxNode() { + if (root == null) { + throw new RuntimeException("树为空"); + } + Node current = root; + while (current.right != null) { + current = current.right; + } + + return current; + } + + + /** + * 从先序遍历和中序遍历中构造出树 + * @param preOrders + * @param inOrders + * @param r + */ + public void getTree(int[] preOrders, int[] inOrders,Node r) { + int root = preOrders[0]; + r.data = root; + + int index = findIndex(inOrders, root); + int[] left = new int[index]; + int[] preLeft = new int[index]; + if (left.length != 0) { + for (int i = 0; i < index; i++) { + left[i] = inOrders[i]; + preLeft[i] = preOrders[i + 1]; + } + Node node = new Node(preLeft[0]); + r.left = node; + } + + + int size = inOrders.length - index - 1; + int[] right = new int[inOrders.length - index - 1]; + int[] preRight = new int[size]; + if (right.length != 0) { + for (int i = 0; i < size; i++) { + right[i] = inOrders[i + index + 1]; + preRight[i] = preOrders[preLeft.length + i + 1]; + } + Node node = new Node(preRight[0]); + r.right = node; + } + + if (preLeft.length != 0) { + getTree(preLeft, left,r.left); + } + + if (preRight.length != 0) { + getTree(preRight, right,r.right); + } + } + + public static class Node { + public int data; + public Node left; + public Node right; + + public Node(int data) { + this.data = data; + } + } + + public Node getRoot() { + return root; + } + + private int findIndex(int[] nums, int target) { + for (int i = 0 ; i < nums.length;i++) { + if (nums[i] == target) { + return i; + } + } + return -1; + } +} diff --git a/src/main/java/cn/byhieg/algorithmtutorial/BinaryTree.java b/src/main/java/cn/byhieg/algorithmtutorial/BinaryTree.java new file mode 100644 index 0000000..1b026ed --- /dev/null +++ b/src/main/java/cn/byhieg/algorithmtutorial/BinaryTree.java @@ -0,0 +1,285 @@ +package cn.byhieg.algorithmtutorial; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.Stack; + +/** + * Created by byhieg on 17/4/15. + * Mail to byhieg@gmail.com + */ +public class BinaryTree { + + /** + * 递归的形式实现先续遍历 + * 根-左-右 + * + * @param root + */ + public static void preOrder1(Node root) { + if (root != null) { + System.out.print(root.data + " "); + preOrder1(root.left); + preOrder1(root.right); + } + } + + /** + * 非递归的形式实现先续遍历 + * 根-左-右 + * + * @param root + */ + public static void preOrder2(Node root) { + if (root != null) { + Stack stack = new Stack<>(); + stack.push(root); + while (!stack.isEmpty()) { + Node cur = stack.pop(); + System.out.print(cur.data + " "); + if (cur.right != null) { + stack.push(cur.right); + } + if (cur.left != null) { + stack.push(cur.left); + } + } + } + } + + /** + * 递归实现中序遍历 + * 左-根-右 + * + * @param root + */ + public static void inOrder1(Node root) { + if (root != null) { + inOrder1(root.left); + System.out.print(root.data + " "); + inOrder1(root.right); + } + } + + /** + * 非递归实现中序遍历 + * 左-根-右 + * + * @param root + */ + public static void inOrder2(Node root) { + if (root != null) { + Stack stack = new Stack<>(); + Node cur = root; + while (!stack.isEmpty() || cur != null) { + if (cur == null) { + Node node = stack.pop(); + System.out.print(node.data + " "); + cur = node.right; + } else { + stack.push(cur); + cur = cur.left; + } + + } + } + } + + /** + * 递归实现树的后续遍历 + * 左-右-根 + * + * @param root + */ + public static void postOrder1(Node root) { + if (root != null) { + postOrder1(root.left); + postOrder1(root.right); + System.out.print(root.data + " "); + } + } + + /** + * 非递归试树的后续遍历 + * 左-右-根 + * + * @param root + */ + public static void postOrder2(Node root) { + if (root != null) { + Stack tmpStack = new Stack<>(); + Stack resStack = new Stack<>(); + tmpStack.push(root); + while (!tmpStack.isEmpty()) { + Node cur = tmpStack.pop(); + resStack.push(cur); + if (cur.left != null) { + tmpStack.push(cur.left); + } + if (cur.right != null) { + tmpStack.push(cur.right); + } + } + + while (!resStack.isEmpty()) { + Node cur = resStack.pop(); + System.out.print(cur.data + " "); + } + } + } + + /** + * 层次遍历 + * + * @param root + */ + public static void levelOrder(Node root) { + if (root != null) { + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + Node cur = queue.poll(); + System.out.print(cur.data + " "); + if (cur.left != null) { + queue.offer(cur.left); + } + if (cur.right != null) { + queue.offer(cur.right); + } + } + } + } + + /** + * 统计树的节点数 + * + * @param root + */ + public static int getNodes(Node root) { + if (root == null) { + return 0; + } + return getNodes(root.left) + getNodes(root.right) + 1; + } + + /** + * 得到树的叶子节点的数目 + * @param root + * @return + */ + public static int getLeafs(Node root) { + if (root == null) { + return 0; + } + if (root.right == null && root.left == null) { + return 1; + } + return getLeafs(root.left) + getLeafs(root.right); + + } + + + /** + * 计算树的深度 + * @param root + * @return + */ + public static int getHeight(Node root){ + if (root == null) { + return 0; + } + int leftHeight = getHeight(root.left) + 1; + int rightHeight = getHeight(root.right) + 1; + return leftHeight > rightHeight ? leftHeight : rightHeight; + } + + /** + * 计算第K层的节点数 + * @param root + * @param k + * @return + */ + public static int calcKNodes(Node root, int k) { + if (root == null || k < 0) { + return 0; + } + if (k == 0){ + return 1; + } + return calcKNodes(root.left, k - 1) + calcKNodes(root.right, k - 1); + + } + + /** + * 判断两个树的结构是否相同 + * @param root1 + * @param root2 + * @return + */ + public static boolean isCommon(Node root1, Node root2) { + if (root1 == null && root2 == null) { + return true; + } else if (root1 == null || root2 == null) { + return false; + }else{ + boolean isLeftCommon = isCommon(root1.left, root2.left); + boolean isRightCommon = isCommon(root1.right, root2.right); + return isLeftCommon && isRightCommon; + } + } + + /** + * 得到树的镜像,即对于每一个节点,交换他们的左右孩子节点。 + * @param root + */ + public static void mirror(Node root) { + if (root != null) { + Node tmp = root.left; + root.left = root.right; + root.right = tmp; + mirror(root.left); + mirror(root.right); + } + } + + /** + * 得到两个节点的最近公共祖先节点。 + * 递归左右子树,如果返回的值都不为空,则表示在左右子树各找到一个target,因为最近的祖先就是cur + * 如果有一个为空,则就不为空就是最近公共祖先。 + * @param root + * @param target1 + * @param target2 + * @return + */ + public static Node findLCA(Node root, Node target1, Node target2) { + if (root == null) + return null; + + if (root == target1 || root == target2) { + return root; + } + Node left = findLCA(root.left, target1, target2); + Node right = findLCA(root.right, target1, target2); + if (left != null && right != null) { + return root; + } + return left != null ? left:right; + } + + + + public static class Node { + public int data; + public Node left; + public Node right; + + + public Node(int data) { + this.data = data; + left = null; + right = null; + } + } + + +} diff --git a/src/main/java/cn/byhieg/algorithmtutorial/Find.java b/src/main/java/cn/byhieg/algorithmtutorial/Find.java new file mode 100644 index 0000000..f476fb3 --- /dev/null +++ b/src/main/java/cn/byhieg/algorithmtutorial/Find.java @@ -0,0 +1,83 @@ +package cn.byhieg.algorithmtutorial; + +/** + * Created by shiqifeng on 2017/3/29. + * Mail byhieg@gmail.com + */ +public class Find { + + + /** + * 二查查找算法,要求准确找到目标值,没有找到则是-1. + * 此方法保证在相同元素都满足条件时,取到的是最大的下标 + * 时间复杂度 o(lgN) + * @param nums int型数组,要求有序 + * @return 找到,返回下标,没找到,返回-1 + */ + public int binarySearchFind(int[] nums,int des) { + int length = nums.length; + int low = 0; + int high = length - 1; + while (low <= high) { + int mid = (low + high) / 2; + if (nums[mid] == des) { + return mid; + } else if (nums[mid] < des) { + low = mid + 1; + } else{ + high = mid - 1; + } + } + return -1; + } + + /** + * 给定一个单调不降的数组,查找大于des条件的最小的数 + * @param nums + * @param des + * @return + */ + public int binarySearchMinFind(int[] nums, int des) { + int length = nums.length; + int low = 0; + int high = length - 1; + int mid ; + while (low < high) { + mid = (low + high) / 2; + if (nums[mid] <= des){ + low = mid + 1; + }else{ + high = mid; + } + } + if (nums[high] > des) return high; + return -1; + } + + /** + * 给定一个单调不降的数组,查找小于des条件的最大的数 + * @param nums + * @param des + * @return + */ + public int binarySearchMaxFind(int[] nums, int des) { + int length = nums.length; + int low = 0; + int high = length - 1; + int mid; + int result = -1; + while (low < high) { + mid = low + (high - low + 1) / 2; + if (nums[mid] < des){ + low = mid; + }else{ + high = mid - 1; + } + } + if (nums[low] < des) return low; + return -1; + } + + + +} diff --git a/src/main/java/cn/byhieg/algorithmtutorial/GraphMatrix.java b/src/main/java/cn/byhieg/algorithmtutorial/GraphMatrix.java new file mode 100644 index 0000000..c22fec3 --- /dev/null +++ b/src/main/java/cn/byhieg/algorithmtutorial/GraphMatrix.java @@ -0,0 +1,166 @@ +package cn.byhieg.algorithmtutorial; + +import java.util.*; + +/** + * Created by shiqifeng on 2017/4/5. + * Mail byhieg@gmail.com + */ +public class GraphMatrix { + + Weight[][] graph; + boolean[] isVisited; + + private static final int UNREACH = Integer.MAX_VALUE >> 1; + + public GraphMatrix(Weight[][] graph) { + this.graph = graph; + } + + /** + * 图的BFS,算法流程 + * 1. 首先将begin节点入队 + * 2. 然后判断队列是否为空,不为空,则出队一个元素,输出。 + * 3. 将出队的元素的所有相邻的元素且没有访问的都放进队列中,重复第二步 + *

+ * 广度优先遍历,从V0出发,访问V0的各个未曾访问的邻接点W1,W2,…,Wk;然后,依次从W1,W2,…,Wk出发访问各自未被访问的邻接点; + * + * @param begin + */ + public void BFS(Integer begin) { + isVisited = new boolean[graph.length]; + for (int i = 0; i < isVisited.length; i++) { + isVisited[i] = false; + } + + Queue queue = new LinkedList<>(); + queue.offer(begin); + isVisited[begin] = true; + + while (!queue.isEmpty()) { + int current = queue.poll(); + System.out.print(current + "-->"); + for (int i = 0; i < graph[current].length; i++) { + if (i == begin) { + continue; + } + if (graph[current][i].weight != UNREACH && !isVisited[i]) { + queue.offer(i); + isVisited[i] = true; + } + } + } + System.out.println("结束"); + } + + + /** + * 图的DFS算法,算法流程 + * 1. 从begin节点出发,输出begin节点。 + * 2. 循环遍历所有与begin节点相邻并且没有被访问的节点 + * 3. 找到一个节点,就以他为begin,递归调用DFS + * + * @param begin + */ + public void DFS(Integer begin) { + isVisited = new boolean[graph.length]; + for (int i = 0; i < isVisited.length; i++) { + isVisited[i] = false; + } + doDFS(begin); + System.out.println("结束"); + } + + /** + * 假设给定图G的初态是所有顶点均未曾访问过。 + * 在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下: + * 首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。 + * 若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。 + * 若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。 + * + * @param begin + */ + private void doDFS(Integer begin) { + isVisited[begin] = true; + System.out.print(begin + "-->"); + for (int i = 0; i < graph[begin].length; i++) { + if (graph[begin][i].weight != UNREACH && !isVisited[i]) { + doDFS(i); + } + } + } + + /** + * dijkstra 从指定起点到指定终点的最短路 + * paths变量,key为节点,value为start到key节点的最短路径 + * values变量,key为节点,value为start到key节点的最小值 + * 1. dijkstra的核心思想,是广义搜索,先遍历所有与start相邻的节点,且没有找过的点 + * 2. 找出最短的节点k,然后以最短的节点为中间节点,如果start-k-i的距离短于start-i,则修改start到i的值,并且修改start到i的路径 + * 3. 然后在此基础上,继续从start节点去没有找过的点,重复1 + * @param start + * @param end + */ + public void dijkstra(int start, int end) { + + + int n = graph.length; + isVisited = new boolean[n]; + for (int i = 0; i < n; i++) { + isVisited[i] = false; + } + isVisited[start] = true; + HashMap paths = new HashMap<>(); + HashMap values = new HashMap<>(); + for(int i = 0 ; i < n;i++) { + if (i == start) { + paths.put(start, start + ""); + }else{ + paths.put(i, start + "" + i + ""); + } + } + values.put(start,0); + while (!values.containsKey(end)) { + int k = -1; + int min = UNREACH; + for (int i = 0; i < n; i++) { + if (!isVisited[i] && graph[start][i].weight < min) { + min = graph[start][i].weight; + k = i; + } + } + values.put(k, min); + isVisited[k] = true; + + for (int i = 0; i < n; i++) { + if (!isVisited[i] && graph[start][k].weight + graph[k][i].weight < graph[start][i].weight) { + graph[start][i].weight = graph[start][k].weight + graph[k][i].weight; + String path = paths.get(k); + path += i + ""; + paths.put(i,path); + } + } + } + System.out.println("从起始点 " + start + " 到终点 " + end + " 的最短路"); + String path = paths.get(end); + for(int i = 0; i < path.length();i++) { + System.out.print(path.charAt(i)); + if (i != path.length() - 1){ + System.out.print("-->"); + } + } + System.out.println("最短路径的值为 " + values.get(end)); + } + + + public static class Weight { + int weight; + + public Weight() { + this(UNREACH); + } + + public Weight(int weight) { + this.weight = weight; + } + } +} diff --git a/src/main/java/cn/byhieg/algorithmtutorial/RedBlackTree.java b/src/main/java/cn/byhieg/algorithmtutorial/RedBlackTree.java new file mode 100644 index 0000000..c895f7b --- /dev/null +++ b/src/main/java/cn/byhieg/algorithmtutorial/RedBlackTree.java @@ -0,0 +1,326 @@ +package cn.byhieg.algorithmtutorial; + +/** + * Created by byhieg on 2017/6/24. + * Mail to byhieg@gmail.com + */ + + +/** + * 红黑树,一种通过红黑两种节点来维持二叉搜索树的一种树 + * 这样树比原先的BST而言,不会出现最坏的查找情况是o(N)的情况 + * 但是对于插入和删除的节点而言,就需要调整树的平衡,也就是维持红黑树的定义 + *

+ * 红黑树的定义如下: + * 1. 任何节点要不是黑色要不是红色 + * 2. 根节点是黑色节点 + * 3. 红节点的两个子节点都是黑色节点 + * 4. 空节点是黑色节点 + * 5. 任何一个节点下面遍历其子孙的叶子节点,经过的黑色节点的个数必须相等。 + *

+ * 红黑树也是通过第5点进行维持平衡的,而为了维持平衡,需要对树进行调整,即进行左旋,右旋。 + + */ +public class RedBlackTree { + + Node root; + + public RedBlackTree() { + } + + public RedBlackTree(int value) { + root = new Node(value); + } + + public Node find(int value) { + if (root == null) { + throw new RuntimeException("树是空的"); + } + + Node currentNode = root; + while (currentNode != null && currentNode.getValue() != value) { + if (currentNode.getValue() < value) { + currentNode = currentNode.getLeft(); + } else { + currentNode = currentNode.getRight(); + } + } + + return currentNode; + } + + + public void insertNode(int value) { + Node node = new Node(value); + insertNode(node); + + } + + /** + * 插入节点 + * 该方法首先找到要插入的位置,然后设置插入的节点为红色节点 + * 然后因为可能会破坏平衡,因此需要进行平衡调整 + * + * @param node + */ + public void insertNode(Node node) { + int cmp; + Node y = null; + Node x = this.root; + + while (x != null) { + y = x; + cmp = node.getValue() - x.getValue(); + if (cmp < 0) { + x = x.left; + } else { + x = x.right; + } + } + + node.parent = y; + if (y != null) { + cmp = node.getValue() - y.getValue(); + if (cmp < 0) { + y.left = node; + } else { + y.right = node; + } + } else { + this.root = node; + } + + node.isRed = true; + insertFixUp(node); + + } + + /** + * 插入修复: 新插入的节点是红色节点,插入修复操作如果遇到父节点的颜色为黑色则修复结束 + * 也就是说只有在父节点为红色节点的时候才需要插入修复操作 + * 插入修复操作分为3种情况, + * 1. 叔叔节点也为红色节点 + * 2. 叔叔节点为空,且祖父节点,父节点与新节点在一个斜线上 + * 3. 叔叔节点为空,且祖父节点,父节点与新节点不在一个斜线上 + *

+ *

+ * 解决办法:对于第一种,只需要将祖父节点与父节点以及叔叔节点的颜色对调即可。 + * 即原祖父节点是黑色,现在变成红色,父节点与叔叔节点都变成黑色。 + * 对于第二种,我们将新插入的节点为C,父节点为B,祖父节点为A. + * 如果BC都是左节点,要现将A右旋,然后调整B与A的颜色,即B变成黑色,A变成红色 + * 如果BC都是右节点,要现将A左旋,然后调整B与A的颜色,即B变成黑色,A变成红色 + * 对于第三种,我们将新插入的节点为C,父节点为B,祖父节点为A. + * 如果C为右节点,B为左节点,要先将B左旋,然后就变成第二种的情况 + * 如果C为左节点,B为右节点,要先B右旋,然后就变成第二种的情况 + * + * @param node + */ + private void insertFixUp(Node node) { + Node parent, grandParent, uncle; + while ((parent = parentOf(node)) != null && parent.isRed()) { + grandParent = parentOf(node); + //如果父节点是祖父节点的左孩子 + if (parent == grandParent.left) { + uncle = grandParent.right; + //第一种情况 + if ((uncle != null) && uncle.isRed()) { + uncle.makeBlack(); + parent.makeBlack(); + grandParent.makeRed(); + node = grandParent; + continue; + } + //将第三种情况变成第二种情况 + if (parent.right == node) { + Node tmp; + rotateLeft(parent); + tmp = parent; + parent = node; + node = tmp; + } + parent.makeBlack(); + grandParent.makeRed(); + rotateRight(grandParent); + } else { + uncle = grandParent.left; + if ((uncle != null) && uncle.isRed()) { + uncle.makeBlack(); + parent.makeBlack(); + grandParent.makeRed(); + node = grandParent; + continue; + } + + if (parent.left == node) { + Node tmp; + rotateRight(parent); + tmp = parent; + parent = node; + node = tmp; + } + + parent.makeBlack(); + grandParent.makeRed(); + rotateLeft(grandParent); + + } + + } + + root.makeBlack(); + } + + + /** + * 对红黑树的节点(y)进行右旋转 + * + * 右旋示意图(对节点y进行左旋): + * py py + * / / + * y x + * / \ --(右旋)-. / \ # + * x ry lx y + * / \ / \ # + * lx rx rx ry + * + * @param y 待旋转的节点 + */ + private void rotateRight(Node y) { + + Node x = y.left; + + // 将 “x的右孩子” 设为 “y的左孩子”; + // 如果"x的右孩子"不为空的话,将 “y” 设为 “x的右孩子的父亲” + y.left = x.right; + if (x.right != null) + x.right.parent = y; + + // 将 “y的父亲” 设为 “x的父亲” + x.parent = y.parent; + + if (y.parent == null) { + this.root = x; // 如果 “y的父亲” 是空节点,则将x设为根节点 + } else { + if (y == y.parent.right) + y.parent.right = x; // 如果 y是它父节点的右孩子,则将x设为“y的父节点的右孩子” + else + y.parent.left = x; // (y是它父节点的左孩子) 将x设为“x的父节点的左孩子” + } + + // 将 “y” 设为 “x的右孩子” + x.right = y; + + // 将 “y的父节点” 设为 “x” + y.parent = x; + } + + /** + * + * 对红黑树的节点(x)进行左旋转 + * + * 左旋示意图(对节点x进行左旋): + * px px + * / / + * x y + * / \ --(左旋)-. / \ # + * lx y x ry + * / \ / \ + * ly ry lx ly + * + * @param x 待旋转的节点 + */ + private void rotateLeft(Node x) { + Node y = x.getRight(); + x.right = y.left; + if (y.left != null) { + y.left.parent = x; + } + y.parent = x.parent; + if (x.parent == null) { + root = y; + }else{ + if (x.parent.left == x) { + x.parent.left = y; + }else{ + x.parent.right = y; + } + } + y.left = x; + x.parent = y; + } + + private Node parentOf(Node node) { + return node != null ? node.parent : null; + } + + + static class Node { + private int value; + private Node parent; + private boolean isRed; + private Node left; + private Node right; + + public Node() { + + } + + public Node(int value) { + this.value = value; + + } + + public Node(int value, boolean isRed) { + this.value = value; + this.isRed = isRed; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public Node getParent() { + return parent; + } + + public void setParent(Node parent) { + this.parent = parent; + } + + public boolean isRed() { + return isRed; + } + + public boolean isBlack() { + return !isRed(); + } + + public Node getLeft() { + return left; + } + + public void setLeft(Node left) { + this.left = left; + } + + public Node getRight() { + return right; + } + + public void setRight(Node right) { + this.right = right; + } + + public void makeRed() { + isRed = true; + } + + public void makeBlack() { + isRed = false; + } + } +} diff --git a/src/main/java/cn/byhieg/algorithmtutorial/SingleLinkList.java b/src/main/java/cn/byhieg/algorithmtutorial/SingleLinkList.java new file mode 100644 index 0000000..1de9643 --- /dev/null +++ b/src/main/java/cn/byhieg/algorithmtutorial/SingleLinkList.java @@ -0,0 +1,109 @@ +package cn.byhieg.algorithmtutorial; + +/** + * Created by byhieg on 17/5/2. + * Mail to byhieg@gmail.com + */ +public class SingleLinkList { + + + public Node head; + + /** + * 在当前链表尾部插入一个节点 + * + * @param data + * @return + */ + public Node insertFromTail(int data) { + Node cur = getHead(); + Node node = new Node(data); + if (cur == null) { + head = node; + return head; + } else { + while (cur.next != null) { + cur = cur.next; + } + cur.next = node; + } + return cur; + } + + /** + * 在当前链表头部插入一个节点 + * + * @param data + * @return + */ + public Node insertFromHead(int data) { + Node node = new Node(data); + node.next = head; + head = node; + return head; + } + + /** + * 反转链表的非递归实现 + * @return + */ + public Node reverseLinkList() { + if (head == null) { + return head; + } + Node reverseHead = null; + Node cur = head; + Node prev = null; + while (cur != null) { + Node next = cur.next; + if (next == null) { + reverseHead = cur; + } + cur.next = prev; + prev = cur; + cur = next; + } + return reverseHead; + } + + + /** + * 反转链表的递归实现 + * @return + */ + public Node reverseLinkList(Node head){ + if (head == null || head.next == null) { + return head; + } + Node newNode = reverseLinkList(head.next); + head.next.next = head; + head.next = null; + return newNode; + } + + + + /** + * 打印链表 + */ + public void printLinkList(Node head) { + Node cur = head; + while (cur != null) { + System.out.print(cur.data + " "); + cur = cur.next; + } + } + + public Node getHead() { + return head; + } + + public static class Node { + public int data; + public Node next; + + public Node(int data) { + this.data = data; + } + } +} diff --git a/src/main/java/cn/byhieg/algorithmtutorial/Sort.java b/src/main/java/cn/byhieg/algorithmtutorial/Sort.java new file mode 100644 index 0000000..6794e42 --- /dev/null +++ b/src/main/java/cn/byhieg/algorithmtutorial/Sort.java @@ -0,0 +1,320 @@ +package cn.byhieg.algorithmtutorial; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * Created by shiqifeng on 2017/3/28. + * Mail byhieg@gmail.com + */ +public class Sort { + + /** + * 选择排序,每一轮排序,选择数组中数字最小的那一个放到指定的位置上。 + * 时间复杂度o(n^2),无论数组顺序如何都要选择一个最小的值,因为数组的是否有序,不影响时间复杂度 + * 空间复杂度o(1) + * 不稳定排序 + * @param nums + */ + public void chooseSort(int[] nums) { + int length = nums.length; + for (int i = 0; i < length; i++) { + int min = i;//申请额外的空间o(1) + for (int j = i + 1; j < length; j++) { + if (nums[min] > nums[j]) { + min = j; + } + } + //将最小的下标代表的数与i位置的进行交换 + int tmp = nums[i]; + nums[i] = nums[min]; + nums[min] = tmp; + } + } + + /** + * 直接插入排序,每一轮排序,都是在i坐标之前,包括i坐标的序列是有序的,但是并不是最终的排序位置。 + * 时间复杂度o(n^2),对于第二重循环,只会在非有序的环境下才会执行每个元素后移,因此针对有序的数组,时间复杂度最好的情况是o(N)。 + * 空间复杂度o(1) + * 稳定排序 + * @param nums + */ + public void insertDirectlySort(int[] nums) { + int length = nums.length; + for (int i = 1; i < length; i++) { + for (int j = i; j > 0; j--) { + //这一步导致该算法是稳定排序 + if (nums[j] < nums[j - 1]) { + int tmp = nums[j - 1]; + nums[j - 1] = nums[j]; + nums[j] = tmp; + } + } + } + } + + /** + * 折半插入排序,针对直接排序而言,每一个要插入的元素都是插入在有序的数组中,因此,只需要查找到插入的位置即可,查找的方式利用二分查找 + * 时间复杂度和直接插入是一样的,只是快在了查找的过程中,还是o(N^2),最好的环境下是o(N) + * 空间复杂度还是o(1) + * + * @param nums + */ + public void insertBinarySort(int[] nums) { + int length = nums.length; + for (int i = 1; i < length; i++) { + int tmp = nums[i]; + int low = 0; + int high = i - 1; + while (low <= high) { + int mid = (low + high) / 2; + if (tmp < nums[mid]) { + high = mid - 1; + } else { + low = mid + 1; + } + } + + for (int j = i; j >= low + 1; j--) { + nums[j] = nums[j - 1]; + } + nums[low] = tmp; + } + } + + /** + * 冒泡排序,每i轮排序,就是不断交换两个元素,直到将最大的元素放到n - i的位置上 + * 这种实现是按照算法定义的,但是效率是最低的 + * 时间复杂度o(n^2) + * 空间复杂度o(1) + * 稳定排序 + * @param nums + */ + public void bubbleSort1(int[] nums) { + int length = nums.length; + for (int i = 1; i < length; i++) { + for (int j = 0; j < length - i; j++) { + //这一步导致该算法是稳定排序 + if (nums[j] > nums[j + 1]) { + int tmp = nums[j]; + nums[j] = nums[j + 1]; + nums[j + 1] = tmp; + } + } + } + } + + /** + * 冒泡排序,高效率实现,因为只需要用一个flag变量来记录本次的排序,是否修改 + * 如果没有修改,说明已经有序 + * + * @param nums + */ + public void bubbleSort2(int[] nums) { + int length = nums.length; + boolean flag = true; + while (flag) { + flag = false; + for (int j = 0; j < length - 1; j++) { + if (nums[j] > nums[j + 1]) { + int tmp = nums[j]; + nums[j] = nums[j + 1]; + nums[j + 1] = tmp; + flag = true; + } + } + length--; + } + } + + /** + * 归并排序,将数组一分为二,对于每一子数组继续进行上述步骤,直到子数组只有1个元素,那么自然是有序的。 + * 然后不断合并两个数组,直到合并到整个数组。 + * 时间复杂度o(NlgN) + * 空间复杂度o(N) + * @param nums + */ + public void mergeSort(int[] nums) { + int length = nums.length; + int low = 0; + int high = length - 1; + realSort(nums, low, high); + } + + /** + * 归并排序真正的sort函数 + * @param nums 待排序的数组 + * @param low 最低位 + * @param high 最高位 + */ + private void realSort(int[] nums, int low, int high) { + int mid = (low + high) / 2; + if (low < high) { + realSort(nums, low, mid); + realSort(nums, mid + 1, high); + realMerge(nums, low, mid, high); + } + } + + private void realMerge(int[] nums, int low, int mid, int high) { + int[] tmpNums = new int[high - low + 1]; + int leftPoint = low; + int rightPoint = mid + 1; + int index = 0; + + while (leftPoint <= mid && rightPoint <= high) { + if (nums[leftPoint] < nums[rightPoint]) { + tmpNums[index++] = nums[leftPoint++]; + }else{ + tmpNums[index++] = nums[rightPoint++]; + } + } + + while (leftPoint <= mid) { + tmpNums[index++] = nums[leftPoint++]; + } + while (rightPoint <= high) { + tmpNums[index++] = nums[rightPoint++]; + } + + System.arraycopy(tmpNums, 0, nums, low, tmpNums.length); + } + + /** + * 快速排序,选定一个切分元素,每一轮排序后,都保证切分元素之前的元素都小于切分元素,切分元素之后的元素都大于切分元素 + * 时间复杂度o(NlgN) + * 空间复杂度o(lgN) + * 不稳定排序 + * @param nums + */ + public void quickSort(int[] nums) { + int low = 0; + int high = nums.length - 1; + sort(nums, low, high); + } + + /** + * 快速排序的递归实现 + * + * @param nums + * @param low + * @param high + */ + public void sort(int[] nums, int low, int high) { + if (low >= high) return; + int j = partition(nums, low, high); + sort(nums, low, j - 1); + sort(nums, j + 1, high); + } + + /** + * 快速排序的辅助方法,来对排序的数组,进行切分, + * + * @param nums + * @param low + * @param high + * @return + */ + public int partition(int[] nums, int low, int high) { + int i = low; + int j = high; + int x = nums[i]; + while (i < j) { + //从右向左找到nums[j]小于x的元素 + while (i < j && nums[j] >= x) j--; + if (i < j) { + nums[i] = nums[j]; + i++; + } + + //从左向右找到nums[i]大于x的元素 + while (i < j && nums[i] <= x) i++; + if (i < j) { + nums[j] = nums[i]; + j--; + } + } + nums[i] = x; + return i; + } + + + /** + * 堆排序,建立一个小顶堆,小顶堆满足父节点比两个子节点的值要小 + * 堆的性质满足:1. 只能在堆顶删除元素 + * 2. 只能在堆的最后一位存元素。 + * 3. 堆的存储利用数组,满足i节点是父节点,则子节点是2 * i+ 1,2 * i + 2 + * 4. 堆的两种建方法,第一种是从上到下,@see sink(),第二种是从下到上 @see swim + * 5. 堆排序是指在弄好的堆中,输出第一个元素,然后将最后一个元素与第一个元素互换,换后调用sink,找到自己的位置后,在重复这个步骤,就输出一个有序的堆 + * 6. 如果要生序就需要大顶堆,要降序就需要小顶堆。 + * 时间复杂度:o(NlgN) + * 空间复杂度: o(1) + * 这是小顶堆的排序,所以nums数组最后是降序的 + * 不稳定,不稳定的原因在建堆的时候,就可能把相同元素的位置换了,比如两个相同元素在不同的子树上 + * @param nums + */ + public void heapSort(int[] nums) { + int length = nums.length; +// for (int i = 0; i < length; i++) { +// swim(nums, i); +// } + //只能从前一半开始sink + for (int i = length / 2 ; i >= 0;i--) { + sink(nums,i,length); + } + while (length > 0) { + int temp = nums[0]; + nums[0] = nums[length - 1]; + nums[length - 1] = temp; + length--; + sink(nums, 0, length); + } + } + + /** + * 将i放入对堆中,i的父节点是(i - 1)/ 2,父节点的值是小于他的两个子节点的 + * i节点放入后,要向上移动,如果父节点比i节点的值大,则i节点要继续上移。 + * + * @param nums + * @param i + */ + private void swim(int nums[], int i) { + while (i > 0) { + int father = (i - 1) / 2; + if (nums[father] > nums[i]) { + int temp = nums[father]; + nums[father] = nums[i]; + nums[i] = temp; + } + i = father; + } + } + + + /** + * 从i节点由上到下开始调整,i节点的子节点为2*i + 1, 2 * i + 2 + * i节点要向下移动,直到满足i节点小于两个子节点 + * + * @param nums nums[] 数组 + * @param i i节点 + */ + public void sink(int [] nums, int i,int n) { + int son = 2 * i + 1; + while (son <= n - 1) { + if (son < n - 1 && nums[son] > nums[son + 1]) son++; + if (nums[i] > nums[son]) { + int temp = nums[i]; + nums[i] = nums[son]; + nums[son] = temp; + i = son; + son = 2 * i + 1; + }else{ + break; + } + } + } + + + +} diff --git a/src/main/java/cn/byhieg/annotationstutorial/AConstructor.java b/src/main/java/cn/byhieg/annotationstutorial/AConstructor.java new file mode 100644 index 0000000..05752cc --- /dev/null +++ b/src/main/java/cn/byhieg/annotationstutorial/AConstructor.java @@ -0,0 +1,20 @@ +package cn.byhieg.annotationstutorial; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by byhieg on 17/2/14. + * Mail to byhieg@gmail.com + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.CONSTRUCTOR) +public @interface AConstructor { + + public String initName() default "byhieg"; + + public int initAge() default 24; + +} diff --git a/src/main/java/cn/byhieg/annotationstutorial/AConstructorProcess.java b/src/main/java/cn/byhieg/annotationstutorial/AConstructorProcess.java new file mode 100644 index 0000000..7f182f5 --- /dev/null +++ b/src/main/java/cn/byhieg/annotationstutorial/AConstructorProcess.java @@ -0,0 +1,31 @@ +package cn.byhieg.annotationstutorial; + +import javax.jws.soap.SOAPBinding; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * Created by byhieg on 17/2/14. + * Mail to byhieg@gmail.com + */ +public class AConstructorProcess { + + public static void init(Object object) throws IllegalAccessException, InvocationTargetException, InstantiationException { + if (object instanceof User) { + Class clz = object.getClass(); + Constructor [] constructors = clz.getConstructors(); + for (Constructor constructor : constructors) { + if (constructor.isAnnotationPresent(AConstructor.class)) { + AConstructor aConstructor = (AConstructor) constructor.getAnnotation(AConstructor.class); + String name = aConstructor.initName(); + int age = aConstructor.initAge(); + ((User) object).name = name; + ((User) object).age = age; + } + } + }else{ + throw new RuntimeException("无法向下转型到指定类"); + } + + } +} diff --git a/src/main/java/cn/byhieg/annotationstutorial/AMethod.java b/src/main/java/cn/byhieg/annotationstutorial/AMethod.java new file mode 100644 index 0000000..2a73b74 --- /dev/null +++ b/src/main/java/cn/byhieg/annotationstutorial/AMethod.java @@ -0,0 +1,18 @@ +package cn.byhieg.annotationstutorial; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by byhieg on 17/2/14. + * Mail to byhieg@gmail.com + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface AMethod { + public String method(); + + public String value(); +} diff --git a/src/main/java/cn/byhieg/annotationstutorial/AMethodProcess.java b/src/main/java/cn/byhieg/annotationstutorial/AMethodProcess.java new file mode 100644 index 0000000..3494539 --- /dev/null +++ b/src/main/java/cn/byhieg/annotationstutorial/AMethodProcess.java @@ -0,0 +1,33 @@ +package cn.byhieg.annotationstutorial; + + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Created by byhieg on 17/2/14. + * Mail to byhieg@gmail.com + */ +public class AMethodProcess { + + public static void initMethod(Object object) throws InvocationTargetException, IllegalAccessException { + if (object instanceof User) { + Class clz = object.getClass(); + Method [] methods = clz.getDeclaredMethods(); + for (Method method : methods) { + if (method.isAnnotationPresent(AMethod.class)) { + if(Modifier.isPrivate(method.getModifiers())){ + method.setAccessible(true); + }else { + AMethod aMethod = method.getAnnotation(AMethod.class); + System.out.println(aMethod.method() + "时间为 " + aMethod.value()); + method.invoke(object); + } + } + } + }else { + throw new RuntimeException("无法向下转型成指定类"); + } + } +} diff --git a/src/main/java/cn/byhieg/annotationstutorial/APTAnnotation.java b/src/main/java/cn/byhieg/annotationstutorial/APTAnnotation.java new file mode 100644 index 0000000..e9e9458 --- /dev/null +++ b/src/main/java/cn/byhieg/annotationstutorial/APTAnnotation.java @@ -0,0 +1,21 @@ +package cn.byhieg.annotationstutorial; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by byhieg on 17/2/14. + * Mail to byhieg@gmail.com + */ + +@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD}) +@Retention(RetentionPolicy.SOURCE) +public @interface APTAnnotation { + String author() default "byhieg"; + + String date(); + + String version() default "1"; +} diff --git a/src/main/java/cn/byhieg/annotationstutorial/APTProcessor.java b/src/main/java/cn/byhieg/annotationstutorial/APTProcessor.java new file mode 100644 index 0000000..de6707e --- /dev/null +++ b/src/main/java/cn/byhieg/annotationstutorial/APTProcessor.java @@ -0,0 +1,109 @@ +package cn.byhieg.annotationstutorial; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Messager; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; +import java.util.Set; + +/** + * Created by byhieg on 17/2/14. + * Mail to byhieg@gmail.com + */ +public class APTProcessor extends AbstractProcessor{ + + //类名的前缀、后缀 + public static final String SUFFIX = "AutoGenerate"; + public static final String PREFIX = "byhieg_"; + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (TypeElement typeElement : annotations) { + for (Element e : roundEnv.getElementsAnnotatedWith(typeElement)) { + //打印消息 + Messager messager = processingEnv.getMessager(); + messager.printMessage(Diagnostic.Kind.NOTE, "Printing:" + e.toString()); + messager.printMessage(Diagnostic.Kind.NOTE, "Printing:" + e.getSimpleName()); + messager.printMessage(Diagnostic.Kind.NOTE, "Printing:" + e.getEnclosedElements().toString()); + + //获取注解 + APTAnnotation aptAnnotation = e.getAnnotation(APTAnnotation.class); + + //获取元素名并将其首字母大写 + String name = e.getSimpleName().toString(); + char c = Character.toUpperCase(name.charAt(0)); + name = String.valueOf(c + name.substring(1)); + + //包裹注解元素的元素, 也就是其父元素, 比如注解了成员变量或者成员函数, 其上层就是该类 + Element enclosingElement = e.getEnclosingElement(); + String enclosingQualifiedname; + if (enclosingElement instanceof PackageElement) { + enclosingQualifiedname = ((PackageElement) enclosingElement).getQualifiedName().toString(); + } else { + enclosingQualifiedname = ((TypeElement) enclosingElement).getQualifiedName().toString(); + } + try { + //生成包名 + String generatePackageName = enclosingQualifiedname.substring(0, enclosingQualifiedname.lastIndexOf(".")); + + // 生成的类名 + String genarateClassName = PREFIX + enclosingElement.getSimpleName() + SUFFIX; + + //创建Java 文件 + JavaFileObject f = processingEnv.getFiler().createSourceFile(genarateClassName); + + // 在控制台输出文件路径 + messager.printMessage(Diagnostic.Kind.NOTE, "Printing: " + f.toUri()); + Writer w = f.openWriter(); + try { + PrintWriter pw = new PrintWriter(w); + pw.println("package " + generatePackageName + ";"); + pw.println("\npublic class " + genarateClassName + " { "); + pw.println("\n /** 打印值 */"); + pw.println(" public static void print" + name + "() {"); + pw.println(" // 注解的父元素: " + enclosingElement.toString()); + pw.println(" System.out.println(\"代码生成的路径: " + f.toUri() + "\");"); + pw.println(" System.out.println(\"注解的元素: " + e.toString() + "\");"); + pw.println(" System.out.println(\"注解的版本: " + aptAnnotation.version() + "\");"); + pw.println(" System.out.println(\"注解的作者: " + aptAnnotation.author() + "\");"); + pw.println(" System.out.println(\"注解的日期: " + aptAnnotation.date() + "\");"); + + pw.println(" }"); + pw.println("}"); + pw.flush(); + } finally { + w.close(); + } + } catch (IOException e1) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e1.toString()); + } + } + } + return true; + } + + + @Override + public Set getSupportedAnnotationTypes() { + return super.getSupportedAnnotationTypes(); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + } +} diff --git a/src/main/java/cn/byhieg/annotationstutorial/ReadMe.md b/src/main/java/cn/byhieg/annotationstutorial/ReadMe.md new file mode 100644 index 0000000..d01329d --- /dev/null +++ b/src/main/java/cn/byhieg/annotationstutorial/ReadMe.md @@ -0,0 +1,14 @@ +# Java 注解 + +Java注解是Java1.5以后提供用来标注类,变量,方法等,其目的在于给这些类,变量,方法提供形式化的信息。 +注解的写法和用法都是大同小异,一个格式,因此这篇注解的主要内容,是提供一些比较好的注解方面的文章。 + +在[源码](https://github.com/byhieg/JavaTutorial/tree/master/src/main/java/cn/byhieg/annotationstutorial)中提供了构造器和方法的运行时注解和一个APT编译前注解的例子。 + +注解相关的文章: + +- [注解的讲解](http://blog.csdn.net/dd864140130/article/details/53875814) +- [APT的讲解](https://github.com/OriginalLove/JavaAdvanced/blob/master/Java%E6%B3%A8%E8%A7%A3%E4%BA%8C.md) + + + diff --git a/src/main/java/cn/byhieg/annotationstutorial/User.java b/src/main/java/cn/byhieg/annotationstutorial/User.java new file mode 100644 index 0000000..bfa28e9 --- /dev/null +++ b/src/main/java/cn/byhieg/annotationstutorial/User.java @@ -0,0 +1,27 @@ +package cn.byhieg.annotationstutorial; + +/** + * Created by byhieg on 17/2/14. + * Mail to byhieg@gmail.com + */ +public class User { + + public String name; + public int age; + + @AConstructor + public User(){ + + } + + @Override + public String toString() { + return "名字是 " + name + "年龄是 " + age; + } + + @AMethod(method = "Sleep",value = "60m") + public void doSomeThing(){ + System.out.println("做一些事情"); + } + +} diff --git a/src/main/java/cn/byhieg/bitoperatetutorial/BitOperate.java b/src/main/java/cn/byhieg/bitoperatetutorial/BitOperate.java new file mode 100644 index 0000000..680408b --- /dev/null +++ b/src/main/java/cn/byhieg/bitoperatetutorial/BitOperate.java @@ -0,0 +1,14 @@ +package cn.byhieg.bitoperatetutorial; + +/** + * Created by byhieg on 2017/6/27. + * Mail to byhieg@gmail.com + */ +public class BitOperate { + + + public String getRightestOne(int n){ + int res = n & (~n + 1); + return Integer.toBinaryString(res); + } +} diff --git a/src/main/java/cn/byhieg/collectiontutorial/listtutorial/ArrayListDemo.java b/src/main/java/cn/byhieg/collectiontutorial/listtutorial/ArrayListDemo.java new file mode 100644 index 0000000..9d87a9a --- /dev/null +++ b/src/main/java/cn/byhieg/collectiontutorial/listtutorial/ArrayListDemo.java @@ -0,0 +1,31 @@ +package cn.byhieg.collectiontutorial.listtutorial; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Created by byhieg on 17/2/7. + * Mail to byhieg@gmail.com + */ +public class ArrayListDemo { + + private ArrayList listA = new ArrayList<>(); + private ArrayList listB = new ArrayList<>(5); + private ArrayList listC; + + public ArrayList getListA() { + return listA; + } + + public ArrayList getListB() { + return listB; + } + + public ArrayList getListC() { + return listC; + } + + public void setListC(Collection collection) { + listC = new ArrayList<>(collection); + } +} diff --git a/src/main/java/cn/byhieg/collectiontutorial/listtutorial/LinkedListDemo.java b/src/main/java/cn/byhieg/collectiontutorial/listtutorial/LinkedListDemo.java new file mode 100644 index 0000000..8ed9d9a --- /dev/null +++ b/src/main/java/cn/byhieg/collectiontutorial/listtutorial/LinkedListDemo.java @@ -0,0 +1,20 @@ +package cn.byhieg.collectiontutorial.listtutorial; + +import java.util.LinkedList; + +/** + * Created by byhieg on 17/2/15. + * Mail to byhieg@gmail.com + */ +public class LinkedListDemo { + + private LinkedList list = new LinkedList(); + + public LinkedList getList() { + return list; + } + + public void setList(LinkedList list) { + this.list = list; + } +} diff --git a/src/main/java/cn/byhieg/collectiontutorial/listtutorial/README.md b/src/main/java/cn/byhieg/collectiontutorial/listtutorial/README.md new file mode 100644 index 0000000..a4a1f5a --- /dev/null +++ b/src/main/java/cn/byhieg/collectiontutorial/listtutorial/README.md @@ -0,0 +1,493 @@ +# 自动动手系列——实现List +该包代码 主要实现了ArrayList与LinkedList。该README对应介绍实现的内容与过程。下面分别是ArrayList与LinkedList实现 +其ArrayList实现的内容和过程如下: + +# 自己动手系列——实现一个简单的ArrayList +ArrayList是Java集合框架中一个经典的实现类。他比起常用的数组而言,明显的优点在于,可以随意的添加和删除元素而不需考虑数组的大小。处于练手的目的,实现一个简单的ArrayList,并且把实现的过程在此记录。 +实现的ArrayList主要的功能如下: + +- 默认构造器和一个参数的有参构造器 +- add方法 +- get方法 +- indexOf方法 +- contains方法 +- size方法 +- isEmpty方法 +- remove方法 +- sort方法 + +这个简单的ArrayList类 取名为`SimpleArrayList`,全部的代码查看[SimpleArrayList代码](https://github.com/byhieg/JavaTutorial/tree/master/src/main/java/cn/byhieg/collectiontutorial/listtutorial) + +## 构造器 + +源码ArrayList一共有三个构造器,一个无参构造器,一个参数为int型有参构造器,一个参数为Collection型的有参构造器。参数为Collection型的构造器用来实现将其他继承Collection类的容器类转换成ArrayList。SimpleArrayList类因为还没有手动实现其他的容器类,所以实现的构造方法只有2个。代码如下: + +``` + public SimpleArrayList(){ + this(DEFAULT_CAPACITY); + } + + + public SimpleArrayList(int size){ + if (size < 0){ + throw new IllegalArgumentException("默认的大小" + size); + }else{ + elementData = new Object[size]; + } + } +``` + +无参构造器中的 `DEFAULT_CAPACITY`是定义的私有变量,默认值是10,用来创建一个大小为10的数组。有参构造器中,int参数是用来生成一个指定大小的Object数组。将创建好的数组传给`elementData`。`elementData`是真正的用来存储元素的数组。 + +## add方法 +add 方法用来往容器中添加元素,add方法有两个重载方法,一个是add(E e),另一个是add(int index, E e)。add本身很简单,但是要处理动态数组,即数组大小不满足的时候,扩大数组的内存。具体的代码如下: + +``` + public void add(E e){ + isCapacityEnough(size + 1); + elementData[size++] = e; + } +``` + +方法`isCapacityEnough`就是来判断是否需要扩容,传入的参数就是最小的扩容空间。因为add一个元素,所以最小的扩容空间,即新的长度是所有元素+ 1。这里的size就是真正的元素个数。 + +``` + private void isCapacityEnough(int size){ + if (size > DEFAULT_CAPACITY){ + explicitCapacity(size); + } + if (size < 0){ + throw new OutOfMemoryError(); + } + } +``` +判断扩容的方法也很简单,判断需要扩容的空间是不是比默认的空间大。如果需要的空间比默认的空间大,就调用`explicitCapacity`进行扩容。这里有个size小于0的判断,出现size小于0主要是因为当size超过`Integer.MAX_VALUE`就会变成负数。 + +``` + private final static int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8; + + private void explicitCapacity(int capacity){ + int newLength = elementData.length * 2; + if (newLength - capacity < 0){ + newLength = capacity; + } + if (newLength > (MAX_ARRAY_LENGTH)){ + newLength = (capacity > MAX_ARRAY_LENGTH ? Integer.MAX_VALUE : MAX_ARRAY_LENGTH); + } + elementData = Arrays.copyOf(elementData, newLength); + } +``` + +上面的代码是扩容的代码,首先,定义一个数组最大的容量的常量为最大值,这个值按照官方的源码中的解释是要有些VM保留了数组的头部信息在数组中,因此实际存放数据的大小就是整数的最大值 - 8 +然后设定一个要扩容的数组的大小,虽然上面说了有一个扩容空间的值 ** size + 1 ** ,这个是实际我们最小需要扩容的大小。但为了继续增加元素,而不频繁的扩容,因此一次性的申请多一些的扩容空间。这里newLength 打算申请为 数组长度的2倍,然后去判断这个长度是否满足需要的扩容空间的值。 即有了后续的两段代码 + +``` + if (newLength - capacity < 0){ + newLength = capacity; + } + if (newLength > (MAX_ARRAY_LENGTH)){ + newLength = (capacity > MAX_ARRAY_LENGTH ? Integer.MAX_VALUE : MAX_ARRAY_LENGTH); + } +``` + +如果2倍的长度仍然不满足,则申请到需要的扩容长度。在我们只增加一个元素的情况下,这个判断是永远不会生效的,但是如果有addAll方法,则增加的元素很多,就要导致一次申请2倍的长度是不够的。第二个判断是判断newLength的长度如果超过上面定义的数组最大长度则判断要需要的扩容空间是否大于数组最大长度,如果大于则newLength为 ** MAX_VALUE** ,否则为 ** MAX_ARRAY_LENGTH**。 +最后,真正实现数组扩容到设定长度的方法就没意思了,调用`Arrays.copyOf(elementData, newLength)`得到一个扩容后的数组。 +add的另一个重载方法也很简单。 + +``` + public void add(int index, E e) { + //判断是不是越界 + checkRangeForAdd(index); + //判断需不需要扩容 + isCapacityEnough(size + 1); + //将index的元素及以后的元素向后移一位 + System.arraycopy(elementData,index,elementData,index + 1,size - index); + //将index下标的值设为e + elementData[index] = e; + size++; + } +``` + +``` + private void checkRangeForAdd(int index){ + //这里index = size是被允许的,即支持头,中间,尾部插入 + if (index < 0 || index > size){ + throw new IndexOutOfBoundsException("指定的index超过界限"); + } + } +``` +至此,一个简单的add方法就实现完了。 + +## get方法 +get方法用来得到容器中指定下标的元素。方法实现比较简单,直接返回数组中指定下标的元素即可。 + +``` + private void checkRange(int index) { + if (index >= size || index < 0){ + throw new IndexOutOfBoundsException("指定的index超过界限"); + } + } + public E get(int index){ + checkRange(index); + return (E)elementData[index]; + } +``` + + +## indexOf方法 +indexOf方法用来得到指定元素的下标。实现起来比较简单,需要判断传入的元素,代码如下: + +``` + public int indexOf(Object o){ + if (o != null) { + for (int i = 0 ; i < size ; i++){ + if (elementData[i].equals(0)){ + return i; + } + } + }else { + for (int i = 0 ; i < size ; i++){ + if (elementData[i] == null) { + return i; + } + } + } + + return -1; + } +``` + +判断传入的元素是否为null,如果为null,则依次与null。如果不为空,则用`equals`依次比较。匹配成功就返回下标,匹配失败就返回-1。 + +## contains方法 +contains用来判断该容器中是否包含指定的元素。在有了indexOf方法的基础上,contains的实现就很简单了。 + +``` + public boolean contains(Object o){ + return indexOf(o) >= 0; + } +``` +## size方法 +size方法用来得到容器类的元素个数,实现很简单,直接返回size的大小即可。 +``` + public int size(){ + return size; + } +``` + +## isEmpty方法 +isEmpty方法用来判断容器是否为空,判断size方法的返回值是否为0即可。 +``` + public boolean isEmpty(){ + return size() == 0; + } +``` +## remove方法 +remove方法是用来对容器类的元素进行删除,与add一样,remove方法也有两个重载方法,分别是 +remove(Object o)和remove(int index) + +``` + public E remove(int index) { + E value = get(index); + int moveSize = size - index - 1; + if (moveSize > 0){ + System.arraycopy(elementData,index + 1, elementData,index,size - index - 1); + } + elementData[--size] = null; + return value; + } + + public boolean remove(Object o){ + if (contains(o)){ + remove(indexOf(o)); + return true; + }else { + return false; + } + } +``` + +第一个remove方法是核心方法,首先得到要删除的下标元素的值,然后判断index后面的要前移的元素的个数,如果个数大于零,则调用库方法,将index后面的元素向前移一位。最后`elementData[--size] = null;`缩减size大小,并将原最后一位置空。 +第二个remove方法不需要向第一个方法一样,需要告诉使用者要删除的下标对应的元素,只需要判断是否删除成功即可。如果要删除的元素在列表中,则删除成功,如果不在则失败。因此调用`contains`方法就可以判断是否要删除的元素在列表中。在则调用`remove(int index)`,不在则返回失败。 + +## 总结 +自此,一个简单的ArrayList就实现完了,实现的目的是为了弄清ArrayList动态数组的原理以及add与remove方法的内容实现。同时,也清楚了ArrayList最大的扩容空间就是Integer的最大值。该类的所有代码在[SimpleArrayList代码](https://github.com/byhieg/JavaTutorial/tree/master/src/main/java/cn/byhieg/collectiontutorial/listtutorial) + +# 自己动手系列——实现一个简单的LinkedList + +LinkedList与ArrayList都是List接口的具体实现类。LinkedList与ArrayList在功能上也是大体一致,但是因为两者具体的实现方式不一致,所以在进行一些相同操作的时候,其效率也是有差别的。 +对于抽象的数据结构——线性表而言,线性表分为两种,一种是顺序存储结构的顺序表,另一种是通过指针来描述其逻辑位置的链表。 +针对于具体的Java实现: + +- 顺序存储的顺序表是用数组来实现的,以数组为基础进行封装各种操作而形成的List为ArrayList +- 链表是用指针来描述其逻辑位置,在Java中以双向链表为基础进行封装各种操作而形成的List为LinkedList + +针对插入与删除操作,ArrayList每插入一个元素,首先需要判断数组的空间够不够,不够要进行扩容,在有足够的空间的基础上,在指定的index位置上插入元素,但是该index及以后的元素都要后移。虽然删除操作不需要判断空间够不够,但同样需要该index及以后的元素向前移动,这些移动的操作会增加时间的复杂度。但是对于LinkedList就不一样,因为使用指针来指示其逻辑的位置,所以插入与删除的操作的时间复杂度都是 ** O(1) ** + +虽然对于ArrayList而言,插入与删除的时间复杂度很高,但是对于查找指定位置的元素这种操作而言,就非常的快,因为可以通过数组直接得到该下标对应的元素。反而,LinkedList而言,无法直接返回指定位置的元素,需要一个个查询,其时间的复杂度就是 ** O(n) ** + +与实现[ArrayList教程](http://www.cnblogs.com/qifengshi/p/6377614.html)一样,实现的目的主要在于练手以及掌握官方实现的原理和一些技巧,因此很多需要与其他类配合的方法和功能,就先不在这里实现如`iterator`等 + +所以,实现的LinkedList的方法如下: + +- add方法 +- get方法 +- indexOf方法 +- remove方法 + +与实现ArrayList的名字一样,为SimpleLinkedList。[源码地址](https://github.com/byhieg/JavaTutorial/blob/master/src/main/java/cn/byhieg/collectiontutorial/listtutorial/SimpleLinkedList.java),欢迎star,fork + + +## 构建一个双向链表 + +构建的代码如下: + +``` + + private static class Node{ + E item; + Node next; + Node prev; + + public Node(E item, Node next, Node prev) { + this.item = item; + this.next = next; + this.prev = prev; + } + } + +``` + +常规的双向链表的构建方法,一个数字域存放数组,一个前指针指向一个Node类型的元素,一个后指针指向一个Node类型的元素。 + +对于LinkedList的实现而言,还需要以下三个成员变量 + +``` + + private int size; + + private Node first; + + private Node last; + +``` + +## Add方法 +这里实现的add方法是简单的add(E e)以及add(int index,E e)两个方法,addAll()将其他集合转换LinkedList的方法,暂时放到以后去实现。 + +add方法两个重载方法,其分别对应不同的添加方式。先说add(E e)方法的实现。 + +``` + + public boolean add(E element) { + addAtLast(element); + return true; + } + +``` +不指定位置添加元素,则默认添加到了链表的最后。addAtLast的核心代码如下: + +``` + + private void addAtLast(E element) { + Node l = last; + Node node = new Node(element, null, l); + last = node; + if (l == null) { + first = node; + } else { + l.next = node; + } + size++; + } + +``` + +首先找到最后一位的Node元素,然后根据`element`创建一个新的Node元素,其next指向为null,prev指向为最后一位Node元素。在创建完Node元素之后,last就变成了先创建的Node元素,接下来只需要把新node元素加到链表中即可。即让l对象(原最后一位,现倒数第二位元素的next指针,指向新node元素)。至此,新node元素的next指向null,prev指向倒数第二个元素,倒数第二个元素的next指向新node,就将node成功加入链表。 + +上述的操作也可以看出,其插入的操作非常省时间,比起ArrayList,扩容,移动元素快很多。 + +add的第二个重载方法 add(int index ,E e),先看代码实现: + +``` + + public void add(int index, E element) { + checkRangeForAdd(index); + if (index == size) { + addAtLast(element); + } else { + Node l = node(index); + addBeforeNode(element, l); + } + } + +``` + +首先判断要插入的index是否在范围内,在的话,再执行后续的add操作。如果要插入的index刚好是最后一位,则执行上面讲的addAtLast,如果不是,则得到index所对应的Node元素,执行addBeforeNode。 +获取index所对应的Node元素,是node方法,代码如下: + +``` + + private Node node(int index) { + if (index < (size << 1)) { + Node cursor = first; + for (int i = 0; i < index; i++) { + cursor = cursor.next; + } + return cursor; + } else { + Node cursor = last; + for (int i = size - 1; i > index; i--) { + cursor = cursor.prev; + } + return cursor; + } + } + +``` +这里的查找采用二分查找,节省查找时间,而且也应用到了双向链表的特点。首先判断index在前一半的范围内,还是后一半的范围内。如果是前一半,则游标Node初始为first,用游标Node元素的next,不断指向index所在的元素。如果是后一半,则游标Node初始为last,用游标Node元素的prev,不断指向index所在的元素。 + +在指定元素的前面插入新节点的addBeforeNode的方法如下: + +``` + + private void addBeforeNode(E element, Node specifiedNode) { + Node preNode = specifiedNode.prev; + Node newNode = new Node<>(element, specifiedNode, preNode); + if (preNode == null) { + first = newNode; + } else { + preNode.next = newNode; + } + specifiedNode.prev = newNode; + size++; + } + +``` + +插入的方式很简单,新节点的prev是原index元素的prev,新节点的next是原index元素。剩下的操作是把该node放到链表中,让原index元素的prev的next为新节点,但是要判断preNode是不是空,是的话,表示newNode为第一个元素,就是first。 + +至此,一个add方法,就实现完了。 + +## get方法 + +get方法在有了上述node方法之后,就非常的简单。代码如下: + +``` + public E get(int index) { + checkRange(index); + return node(index).item; + } + +``` + +checkRange检查index是否不在范围内。 + +``` + private void checkRange(int index) { + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException("指定index超过界限"); + } + } + +``` + +## indexOf方法 + +indexOf(Object o)用来得到指定元素的下标。 + +``` + + public int indexOf(Object element) { + Node cursor = first; + int count = 0; + while (cursor != null) { + if (element != null) { + if (element.equals(cursor.item)) { + return count; + } + }else{ + if (cursor.item == null) { + return count; + } + } + count ++; + cursor = cursor.next; + } + return -1; + } + + +``` +与ArrayList一样,从第一位开始查找,首先先判断element是不是null,分成两种情况。 + +## remove方法 +remove方法与add方法一样,同样有两个重载的方法,remove(Object o)与remove(int index) + +先看简单的remove(int index)方法,代码如下: + +``` + + public E remove(int index) { + checkRange(index); + return deleteLink(index); + } + +``` + +deleteLink是将该index所对应的节点的链接删除的方法,其代码如下: + +``` + + private E deleteLink(int index) { + Node l = node(index); + E item = l.item; + Node prevNode = l.prev; + Node nextNode = l.next; + + if (prevNode == null) { + first = nextNode; + }else{ + prevNode.next = nextNode; + l.next = null; + } + + if (nextNode == null) { + last = prevNode; + }else{ + nextNode.prev = prevNode; + l.prev = null; + } + size--; + l.item = null; + return item; + } + +``` + +首先获得该index对应的Node元素,得到该Node元素的前一个元素和后一个元素。接下来,只需要将前一个元素和后一个元素直接相连即可,其他只需要额外判断前一个元素和后一个元素是否为null就行。在判断前一个元素是否为null的时候,只需要操作前一个元素,在判断后一个元素是否为null的时候,也只需要操作后一个元素。最后,将要删除的元素各个引用至为null。 + +remove另一个重载方法remove(Object o),在实现了indexOf和deleteLink方法之后,就非常简单。 + +``` + + public boolean remove(Object o) { + int index = indexOf(o); + if (index < 0){ + return false; + } + deleteLink(index); + return true; + } + +``` + +获取该元素对应对应的下标,然后执行deleteLink方法,完成remove操作。 + +## 总结 +至此,一个功能简单的LinkedList就实现完成了,全部的代码可以看[源码地址](https://github.com/byhieg/JavaTutorial/blob/master/src/main/java/cn/byhieg/collectiontutorial/listtutorial/SimpleLinkedList.java),欢迎star,fork。 + + + + + diff --git a/src/main/java/cn/byhieg/collectiontutorial/listtutorial/SimpleArrayList.java b/src/main/java/cn/byhieg/collectiontutorial/listtutorial/SimpleArrayList.java new file mode 100644 index 0000000..0335a6c --- /dev/null +++ b/src/main/java/cn/byhieg/collectiontutorial/listtutorial/SimpleArrayList.java @@ -0,0 +1,132 @@ +package cn.byhieg.collectiontutorial.listtutorial; + +import java.io.Serializable; +import java.lang.annotation.ElementType; +import java.util.Arrays; +import java.util.RandomAccess; + +/** + * Created by byhieg on 17/2/7. + * Mail to byhieg@gmail.com + */ +public class SimpleArrayList implements RandomAccess,Cloneable,Serializable{ + + + private final static int DEFAULT_CAPACITY = 10; + private int size = 0; + + private Object [] elementData; + + public SimpleArrayList(){ + this(DEFAULT_CAPACITY); + } + + + public SimpleArrayList(int size){ + if (size < 0){ + throw new IllegalArgumentException("默认的大小" + size); + }else{ + elementData = new Object[size]; + } + } + + + public void add(E e){ + isCapacityEnough(size + 1); + elementData[size++] = e; + } + + public void add(int index, E e) { + checkRangeForAdd(index); + isCapacityEnough(size + 1); + System.arraycopy(elementData,index,elementData,index + 1,size - index); + elementData[index] = e; + size++; + } + + private void isCapacityEnough(int size){ + if (size > DEFAULT_CAPACITY){ + explicitCapacity(size); + } + if (size < 0){ + throw new OutOfMemoryError(); + } + } + private final static int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8; + + private void explicitCapacity(int capacity){ + int newLength = elementData.length * 2; + if (newLength - capacity < 0){ + newLength = capacity; + } + if (newLength > (MAX_ARRAY_LENGTH)){ + newLength = (capacity > MAX_ARRAY_LENGTH ? Integer.MAX_VALUE : MAX_ARRAY_LENGTH); + } + elementData = Arrays.copyOf(elementData, newLength); + } + + private void checkRangeForAdd(int index){ + if (index < 0 || index > size){ + throw new IndexOutOfBoundsException("指定的index超过界限"); + } + } + + private void checkRange(int index) { + if (index >= size || index < 0){ + throw new IndexOutOfBoundsException("指定的index超过界限"); + } + } + public E get(int index){ + checkRange(index); + return (E)elementData[index]; + } + + public int indexOf(Object o){ + if (o != null) { + for (int i = 0 ; i < size ; i++){ + if (o.equals(elementData[i])){ + return i; + } + } + }else { + for (int i = 0 ; i < size ; i++){ + if (elementData[i] == null) { + return i; + } + } + } + + return -1; + } + + public boolean contains(Object o){ + return indexOf(o) >= 0; + } + + public int size(){ + return size; + } + + public boolean isEmpty(){ + return size() == 0; + } + + public E remove(int index) { + E value = get(index); + int moveSize = size - index - 1; + if (moveSize > 0){ + System.arraycopy(elementData,index + 1, elementData,index,size - index - 1); + } + elementData[--size] = null; + return value; + } + + public boolean remove(Object o){ + if (contains(o)){ + remove(indexOf(o)); + return true; + }else { + return false; + } + } +} diff --git a/src/main/java/cn/byhieg/collectiontutorial/listtutorial/SimpleLinkedList.java b/src/main/java/cn/byhieg/collectiontutorial/listtutorial/SimpleLinkedList.java new file mode 100644 index 0000000..a7a97b4 --- /dev/null +++ b/src/main/java/cn/byhieg/collectiontutorial/listtutorial/SimpleLinkedList.java @@ -0,0 +1,163 @@ +package cn.byhieg.collectiontutorial.listtutorial; + +/** + * Created by byhieg on 17/2/15. + * Mail to byhieg@gmail.com + */ +public class SimpleLinkedList { + + private int size; + + private Node first; + + private Node last; + + + public boolean add(E element) { + addAtLast(element); + return true; + } + + private void addAtLast(E element) { + Node l = last; + Node node = new Node<>(element, null, l); + last = node; + if (l == null) { + first = node; + } else { + l.next = node; + } + size++; + } + + public void add(int index, E element) { + checkRangeForAdd(index); + if (index == size) { + addAtLast(element); + } else { + Node l = node(index); + addBeforeNode(element, l); + } + } + + private void addBeforeNode(E element, Node specifiedNode) { + Node preNode = specifiedNode.prev; + Node newNode = new Node<>(element, specifiedNode, preNode); + if (preNode == null) { + first = newNode; + } else { + preNode.next = newNode; + } + specifiedNode.prev = newNode; + size++; + } + + + private Node node(int index) { + if (index < (size << 1)) { + Node cursor = first; + for (int i = 0; i < index; i++) { + cursor = cursor.next; + } + return cursor; + } else { + Node cursor = last; + for (int i = size - 1; i > index; i--) { + cursor = cursor.prev; + } + return cursor; + } + } + + private void checkRangeForAdd(int index) { + if (index > size || index < 0) { + throw new IndexOutOfBoundsException("指定的index超过界限"); + } + } + + public E get(int index) { + checkRange(index); + return node(index).item; + } + + private void checkRange(int index) { + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException("指定index超过界限"); + } + } + + public int indexOf(Object element) { + Node cursor = first; + int count = 0; + while (cursor != null) { + if (element != null) { + if (element.equals(cursor.item)) { + return count; + } + }else{ + if (cursor.item == null) { + return count; + } + } + count ++; + cursor = cursor.next; + } + return -1; + } + + public E remove(int index) { + checkRange(index); + return deleteLink(index); + } + + public boolean remove(Object o) { + int index = indexOf(o); + if (index < 0){ + return false; + } + deleteLink(index); + return true; + } + + private E deleteLink(int index) { + Node l = node(index); + E item = l.item; + Node prevNode = l.prev; + Node nextNode = l.next; + + if (prevNode == null) { + first = nextNode; + }else{ + prevNode.next = nextNode; + l.next = null; + } + + if (nextNode == null) { + last = prevNode; + }else{ + nextNode.prev = prevNode; + l.prev = null; + } + size--; + l.item = null; + return item; + } + + + + public int size(){ + return size; + } + private static class Node { + E item; + Node next; + Node prev; + + public Node(E item, Node next, Node prev) { + this.item = item; + this.next = next; + this.prev = prev; + + } + } +} diff --git a/src/main/java/cn/byhieg/collectiontutorial/maptutorial/HashMapExample.java b/src/main/java/cn/byhieg/collectiontutorial/maptutorial/HashMapExample.java new file mode 100644 index 0000000..9e55ef1 --- /dev/null +++ b/src/main/java/cn/byhieg/collectiontutorial/maptutorial/HashMapExample.java @@ -0,0 +1,34 @@ +package cn.byhieg.collectiontutorial.maptutorial; + +import java.util.*; + +/** + * Created by shiqifeng on 2017/2/24. + * Mail byhieg@gmail.com + */ +public class HashMapExample { + + public Map insertMap(){ + HashMap maps = new HashMap<>(1); + for (int i = 0 ; i < 10 ;i++) { + maps.put(i + "", i + ""); + } + return maps; + } + + + public void getValue(Map maps,String key) { + System.out.println(maps.get(key)); + } + + + public void getAllKeyAndValue(Map maps) { + Iterator iterator = maps.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = (Map.Entry) iterator.next(); + System.out.print("Key = " + entry.getKey()); + System.out.println(" value = " + entry.getValue()); + } + } + +} diff --git a/src/main/java/cn/byhieg/collectiontutorial/maptutorial/LinkedHashMapExample.java b/src/main/java/cn/byhieg/collectiontutorial/maptutorial/LinkedHashMapExample.java new file mode 100644 index 0000000..f108797 --- /dev/null +++ b/src/main/java/cn/byhieg/collectiontutorial/maptutorial/LinkedHashMapExample.java @@ -0,0 +1,31 @@ +package cn.byhieg.collectiontutorial.maptutorial; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Created by shiqifeng on 2017/2/24. + * Mail byhieg@gmail.com + */ +public class LinkedHashMapExample { + + public LinkedHashMap insertMap(){ + LinkedHashMap maps = new LinkedHashMap<>(); + for (int i = 0 ; i < 10;i++) { + maps.put(i + "", 10 * i + ""); + } + + return maps; + } + + + public void printMaps(LinkedHashMap maps) { + Iterator iterator = maps.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = (Map.Entry) iterator.next(); + System.out.print("key = " + entry.getKey()); + System.out.println(" value = " + entry.getValue()); + } + } +} diff --git a/src/main/java/cn/byhieg/collectiontutorial/maptutorial/README.md b/src/main/java/cn/byhieg/collectiontutorial/maptutorial/README.md new file mode 100644 index 0000000..20e05f9 --- /dev/null +++ b/src/main/java/cn/byhieg/collectiontutorial/maptutorial/README.md @@ -0,0 +1,70 @@ +# 集合Map的讲解 + +Map用于保存具有映射关系的数据,Map里保存着两组数据:key和value,它们都可以使任何引用类型的数据,但key不能重复。所以通过指定的key就可以取出对应的value。Map接口定义了如下常用的方法: + +1. `void clear()`:删除Map中所以键值对。 +2. `boolean containsKey(Object key)`:查询Map中是否包含指定key,如果包含则返回true。 +3. `boolean containsValue(Object value)`:查询Map中是否包含指定value,如果包含则返回true。 +4. `Set entrySet()`:返回Map中所包含的键值对所组成的Set集合,每个集合元素都是Map.Entry对象(Entry是Map的内部类)。 +5. `Object get(Object key)`:返回指定key所对应的value,如Map中不包含key则返回null。 +6. `boolean isEmpty()`:查询Map是否为空,如果空则返回true。 +7. `Set keySet()`:返回该Map中所有key所组成的set集合。 +8. `Object put(Object key,Object value)`:添加一个键值对,如果已有一个相同的key值则新的键值对覆盖旧的键值对。 +9. `void putAll(Map m)`:将指定Map中的键值对复制到Map中。 +10. `Object remove(Object key)`:删除指定key所对应的键值对,返回可以所关联的value,如果key不存在,返回null。 +11. `int size()`:返回该Map里的键值对的个数。 +12. `Collection values()`:返回该Map里所有value组成的Collection。 + +Map中包含一个内部类:Entry。该类封装了一个键值对,它包含了三个方法: + +1. Object getKey():返回该Entry里包含的key值。 +2. Object getValeu():返回该Entry里包含的value值。 +3. Object setValue(V value):设置该Entry里包含的value值,并返回新设置的value值。 + + +## HashMap和Hashtable实现类 +### HashMap与HashTable的区别: + +- 同步性:Hashtable是同步的,这个类中的一些方法保证了Hashtable中的对象是线程安全的。而HashMap则是异步的,因此 HashMap中的对象并不是线程安全的。因为同步的要求会影响执行的效率,所以如果你不需要线程安全的集合那么使用HashMap是一个很好的选择,这 样可以避免由于同步带来的不必要的性能开销,从而提高效率。 +- 值:HashMap可以让你将空值作为一个表的条目的key或value,但是Hashtable是不能放入空值的。HashMap最多只有一个key值为null,但可以有无数多个value值为null。 + + +### 两者的性能 + +HashMap的性能最好,HashTable的性能是最差(因为它是同步的) + +### 注意 +- 用作key的对象必须实现hashCode和equals方法。 +- 不能保证其中的键值对的顺序 +- 尽量不要使用可变对象作为它们的key值。 + +## LinkedHashMap + +它的父类是HashMap,使用双向链表来维护键值对的次序,迭代顺序与键值对的插入顺序保持一致。LinkedHashMap需要维护元素的插入顺序,so性能略低于HashMap,但在迭代访问元素时有很好的性能,因为它是以链表来维护内部顺序。 + + +## TreeMap + +Map接口派生了一个SortMap子接口,SortMap的实现类为TreeMap。TreeMap也是基于红黑树对所有的key进行排序,有两种排序 方式:自然排序和定制排序。Treemap的key以TreeSet的形式存储,对key的要求与TreeSet对元素的要求基本一致。 + +1. `Map.Entry firstEntry()`:返回最小key所对应的键值对,如Map为空,则返回null。 +2. `Object firstKey()`:返回最小key,如果为空,则返回null。 +3. `Map.Entry lastEntry()`:返回最大key所对应的键值对,如Map为空,则返回null。 +4. `Object lastKey()`:返回最大key,如果为空,则返回null。 +5. `Map.Entry higherEntry(Object key)`:返回位于key后一位的键值对,如果为空,则返回null。 +6. `Map.Entry lowerEntry(Object key)`:返回位于key前一位的键值对,如果为空,则返回null。 +7. `Object lowerKey(Object key)`:返回位于key前一位key值,如果为空,则返回null。 +8. `NavigableMap subMap(Object fromKey,boolean fromlnclusive,Object toKey,boolean toInciusive)`:返回该Map的子Map,其key范围从fromKey到toKey。 +9. `SortMap subMap(Object fromKey,Object toKey )`;返回该Map的子Map,其key范围从fromkey(包括)到tokey(不包括)。 +10. `SortMap tailMap(Object fromkey ,boolean inclusive)`:返回该Map的子Map,其key范围大于fromkey(是否包括取决于第二个参数)的所有key。 +11. `SortMap headMap(Object tokey ,boolean inclusive)`:返回该Map的子Map,其key范围小于tokey(是否包括取决于第二个参数)的所有key。 + + +## WeakHashMap +WeakHashMap与HashMap的用法基本相同,区别在于:后者的key保留对象的强引用,即只要HashMap对象不被销毁,其对象所有key所引用的对象不会被垃圾回收,HashMap也不会自动删除这些key所对应的键值对对象。但WeakHashMap的key所引用的对象没有被其他强引 用变量所引用,则这些key所引用的对象可能被回收。WeakHashMap中的每个key对象保存了实际对象的弱引用,当回收了该key所对应的实际对象后,WeakHashMap会自动删除该key所对应的键值对。 + +## IdentityHashMap + +IdentityHashMap与HashMap基本相似,只是当两个key严格相等时,即key1==key2时,它才认为两个key是相等的 。IdentityHashMap也允许使用null,但不保证键值对之间的顺序。 + + diff --git a/src/main/java/cn/byhieg/collectiontutorial/maptutorial/TreeMapExample.java b/src/main/java/cn/byhieg/collectiontutorial/maptutorial/TreeMapExample.java new file mode 100644 index 0000000..136999d --- /dev/null +++ b/src/main/java/cn/byhieg/collectiontutorial/maptutorial/TreeMapExample.java @@ -0,0 +1,86 @@ +package cn.byhieg.collectiontutorial.maptutorial; + + +import java.util.Iterator; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * Created by shiqifeng on 2017/2/24. + * Mail byhieg@gmail.com + */ +public class TreeMapExample { + + public TreeMap insertMap(){ + TreeMap maps = new TreeMap<>(); + + for (int i = 0 ; i < 10;i++) { + maps.put(i + "", 10 * i + ""); + } + + return maps; + } + + public void getSmallestEntry(TreeMap maps){ + Map.Entry entry = maps.firstEntry(); + System.out.println("最小的Entry如下"); + System.out.print("key = " + entry.getKey()); + System.out.println(" value = " + entry.getValue()); + } + + public void getLargestEntry(TreeMap maps){ + Map.Entry entry = maps.lastEntry(); + System.out.println("最大的Entry如下"); + System.out.print("key = " + entry.getKey()); + System.out.println(" value = " + entry.getValue()); + } + + + public void getHigherEntry(TreeMap maps,String key){ + Map.Entry entry = maps.higherEntry(key); + System.out.println("后一个的Entry如下"); + System.out.print("key = " + entry.getKey()); + System.out.println(" value = " + entry.getValue()); + } + + public void getLowestEntry(TreeMap maps, String key) { + Map.Entry entry = maps.lowerEntry(key); + System.out.println("前一个的Entry如下"); + System.out.print("key = " + entry.getKey()); + System.out.println(" value = " + entry.getValue()); + } + + public void getRangeMap(TreeMap maps, String firstKey, String lastKey) { + SortedMap subMaps = maps.subMap(firstKey, lastKey); + Iterator iterator = subMaps.entrySet().iterator(); + System.out.println("子Map如下"); + while (iterator.hasNext()) { + Map.Entry entry = (Map.Entry) iterator.next(); + System.out.print("key = " + entry.getKey()); + System.out.println(" value = " + entry.getValue()); + } + } + + public void getHeadMap(TreeMap maps, String firstKey,boolean isInclusive) { + SortedMap subMaps = maps.headMap(firstKey, isInclusive); + Iterator iterator = subMaps.entrySet().iterator(); + System.out.println(firstKey + "以前" + "所有的Map如下"); + while (iterator.hasNext()) { + Map.Entry entry = (Map.Entry) iterator.next(); + System.out.print("key = " + entry.getKey()); + System.out.println(" value = " + entry.getValue()); + } + } + + public void getTailMap(TreeMap maps, String firstKey,boolean isInclusive) { + SortedMap subMaps = maps.headMap(firstKey, isInclusive); + Iterator iterator = subMaps.entrySet().iterator(); + System.out.println(firstKey + "以后" + "所有的Map如下"); + while (iterator.hasNext()) { + Map.Entry entry = (Map.Entry) iterator.next(); + System.out.print("key = " + entry.getKey()); + System.out.println(" value = " + entry.getValue()); + } + } +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/builder/Person.java b/src/main/java/cn/byhieg/designpatterntutorial/builder/Person.java new file mode 100644 index 0000000..91077fd --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/builder/Person.java @@ -0,0 +1,73 @@ +package cn.byhieg.designpatterntutorial.builder; + +/** + * Created by shiqifeng on 2017/5/7. + * Mail byhieg@gmail.com + */ +public class Person { + + private int age; + private String name; + private int height; + private int weight; + + public int getAge() { + return age; + } + + public String getName() { + return name; + } + + public int getHeight() { + return height; + } + + public int getWeight() { + return weight; + } + + public Person(Builder builder) { + age = builder.age; + name = builder.name; + height = builder.height; + weight = builder.weight; + } + + @Override + public String toString() { + return "age = " + age + " name = " + name + " height = " + height + " weight = " + weight; + } + + public static class Builder{ + + private int age; + private String name; + private int height; + private int weight; + + public Builder setAge(int age) { + this.age = age; + return this; + } + + public Builder setName(String name) { + this.name = name; + return this; + } + + public Builder setHeight(int height) { + this.height = height; + return this; + } + + public Builder setWeight(int weight) { + this.weight = weight; + return this; + } + + public Person build() { + return new Person(this); + } + } +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/builder/SimpleDialog.java b/src/main/java/cn/byhieg/designpatterntutorial/builder/SimpleDialog.java new file mode 100644 index 0000000..0d90062 --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/builder/SimpleDialog.java @@ -0,0 +1,78 @@ +package cn.byhieg.designpatterntutorial.builder; + +/** + * Created by shiqifeng on 2017/5/7. + * Mail byhieg@gmail.com + */ +public class SimpleDialog { + + + public SimpleDialogController controller; + + public SimpleDialog(){ + controller = new SimpleDialogController(); + } + + public void setIcon(String icon) { + controller.setIcon(icon); + } + + public void setTitle(String title) { + controller.setTitle(title); + } + + public void setMessage(String message) { + controller.setMessage(message); + } + + public void setPositiveButton(String positiveButton) { + controller.setPositiveButton(positiveButton); + } + + public void setNegativeButton(String negativeButton) { + controller.setNegativeButton(negativeButton); + } + + + public static class Builder{ + SimpleDialogController.DialogParams P; + + public Builder(){ + P = new SimpleDialogController.DialogParams(); + } + + public Builder setIcon(String icon){ + P.icon = icon; + return this; + } + + public Builder setTitle(String title) { + P.title = title; + return this; + } + + public Builder setMessage(String message) { + P.message = message; + return this; + } + + public Builder setPositiveButton(String positiveButton) { + P.positiveButton = positiveButton; + return this; + } + + public Builder setNegativeButton(String negativeButton) { + P.negativeButton = negativeButton; + return this; + } + + public SimpleDialog create(){ + SimpleDialog dialog = new SimpleDialog(); + P.apply(dialog.controller); + System.out.println(" ICON = " + P.icon + " MESSAGE = " + P.message + " positiveButton = " + P.positiveButton + " negativeButton" + P.negativeButton); + return dialog; + } + } + + +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/builder/SimpleDialogController.java b/src/main/java/cn/byhieg/designpatterntutorial/builder/SimpleDialogController.java new file mode 100644 index 0000000..4d41b74 --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/builder/SimpleDialogController.java @@ -0,0 +1,81 @@ +package cn.byhieg.designpatterntutorial.builder; + +/** + * Created by shiqifeng on 2017/5/7. + * Mail byhieg@gmail.com + */ +public class SimpleDialogController { + + private String icon; + private String title; + private String message; + private String positiveButton; + private String negativeButton; + + public void setIcon(String icon) { + this.icon = icon; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setMessage(String message) { + this.message = message; + } + + public void setPositiveButton(String positiveButton) { + this.positiveButton = positiveButton; + } + + public void setNegativeButton(String negativeButton) { + this.negativeButton = negativeButton; + } + + public String getIcon() { + return icon; + } + + public String getTitle() { + return title; + } + + public String getMessage() { + return message; + } + + public String getPositiveButton() { + return positiveButton; + } + + public String getNegativeButton() { + return negativeButton; + } + + public static class DialogParams{ + public String icon; + public String title; + public String message; + public String positiveButton; + public String negativeButton; + + public void apply(SimpleDialogController controller) { + if (icon != null) { + controller.setIcon(icon); + } + if (title != null) { + controller.setTitle(title); + } + if (message != null) { + controller.setMessage(message); + } + if (positiveButton != null) { + controller.setPositiveButton(positiveButton); + } + if (negativeButton != null) { + controller.setNegativeButton(negativeButton); + } + } + } + +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/Client.java b/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/Client.java new file mode 100644 index 0000000..6d6a78d --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/Client.java @@ -0,0 +1,19 @@ +package cn.byhieg.designpatterntutorial.proxy.dynamicproxy; + + +import java.lang.reflect.Proxy; + +/** + * Created by shiqifeng on 2017/3/17. + * Mail byhieg@gmail.com + */ +public class Client { + + public static void main(String[] args) { + Subject realSubject = new RealSubject(); + DynamicProxy proxy = new DynamicProxy(realSubject); + ClassLoader classLoader = realSubject.getClass().getClassLoader(); + Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new Class[]{Subject.class}, proxy); + subject.visit(); + } +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/DynamicProxy.java b/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/DynamicProxy.java new file mode 100644 index 0000000..5589d9c --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/DynamicProxy.java @@ -0,0 +1,23 @@ +package cn.byhieg.designpatterntutorial.proxy.dynamicproxy; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * Created by shiqifeng on 2017/3/17. + * Mail byhieg@gmail.com + */ +public class DynamicProxy implements InvocationHandler { + private Object object; + + + public DynamicProxy(Object object) { + this.object = object; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Object result = method.invoke(object, args); + return result; + } +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/RealSubject.java b/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/RealSubject.java new file mode 100644 index 0000000..ab391f7 --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/RealSubject.java @@ -0,0 +1,15 @@ +package cn.byhieg.designpatterntutorial.proxy.dynamicproxy; + + +/** + * Created by shiqifeng on 2017/3/17. + * Mail byhieg@gmail.com + */ +public class RealSubject implements Subject { + + private String name = "byhieg"; + @Override + public void visit() { + System.out.println(name); + } +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/Subject.java b/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/Subject.java new file mode 100644 index 0000000..f662e32 --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/proxy/dynamicproxy/Subject.java @@ -0,0 +1,10 @@ +package cn.byhieg.designpatterntutorial.proxy.dynamicproxy; + +/** + * Created by shiqifeng on 2017/3/17. + * Mail byhieg@gmail.com + */ +public interface Subject { + + void visit(); +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/Client.java b/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/Client.java new file mode 100644 index 0000000..7e38f06 --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/Client.java @@ -0,0 +1,13 @@ +package cn.byhieg.designpatterntutorial.proxy.staticproxy; + +/** + * Created by shiqifeng on 2017/3/17. + * Mail byhieg@gmail.com + */ +public class Client { + + public static void main(String[] args) { + ProxySubject subject = new ProxySubject(new RealSubject()); + subject.visit(); + } +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/ProxySubject.java b/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/ProxySubject.java new file mode 100644 index 0000000..9a6ed10 --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/ProxySubject.java @@ -0,0 +1,19 @@ +package cn.byhieg.designpatterntutorial.proxy.staticproxy; + +/** + * Created by shiqifeng on 2017/3/17. + * Mail byhieg@gmail.com + */ +public class ProxySubject implements Subject{ + + private Subject subject; + + public ProxySubject(Subject subject) { + this.subject = subject; + } + + @Override + public void visit() { + subject.visit(); + } +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/RealSubject.java b/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/RealSubject.java new file mode 100644 index 0000000..9669e0b --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/RealSubject.java @@ -0,0 +1,14 @@ +package cn.byhieg.designpatterntutorial.proxy.staticproxy; + +/** + * Created by shiqifeng on 2017/3/17. + * Mail byhieg@gmail.com + */ +public class RealSubject implements Subject { + + private String name = "byhieg"; + @Override + public void visit() { + System.out.println(name); + } +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/Subject.java b/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/Subject.java new file mode 100644 index 0000000..1e93880 --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/proxy/staticproxy/Subject.java @@ -0,0 +1,10 @@ +package cn.byhieg.designpatterntutorial.proxy.staticproxy; + +/** + * Created by shiqifeng on 2017/3/17. + * Mail byhieg@gmail.com + */ +public interface Subject { + + void visit(); +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/singleton/DCLSingleton.java b/src/main/java/cn/byhieg/designpatterntutorial/singleton/DCLSingleton.java new file mode 100644 index 0000000..ba45d43 --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/singleton/DCLSingleton.java @@ -0,0 +1,28 @@ +package cn.byhieg.designpatterntutorial.singleton; + +/** + * Created by shiqifeng on 2017/3/14. + * Mail byhieg@gmail.com + */ +public class DCLSingleton { + + private static volatile DCLSingleton singleton; + + private DCLSingleton(){ + + } + + public static DCLSingleton getSingleton(){ + if (singleton == null) { + synchronized (DCLSingleton.class) { + if (singleton == null) { + singleton = new DCLSingleton(); + } + } + } + return singleton; + } + + + +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/singleton/EnumSingleton.java b/src/main/java/cn/byhieg/designpatterntutorial/singleton/EnumSingleton.java new file mode 100644 index 0000000..86c24cf --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/singleton/EnumSingleton.java @@ -0,0 +1,14 @@ +package cn.byhieg.designpatterntutorial.singleton; + +/** + * Created by shiqifeng on 2017/3/14. + * Mail byhieg@gmail.com + */ +public enum EnumSingleton { + SINGLETON; + + + public void doSometings(){ + + } +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/singleton/HungrySingleton.java b/src/main/java/cn/byhieg/designpatterntutorial/singleton/HungrySingleton.java new file mode 100644 index 0000000..d3ac705 --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/singleton/HungrySingleton.java @@ -0,0 +1,17 @@ +package cn.byhieg.designpatterntutorial.singleton; + +/** + * Created by shiqifeng on 2017/3/14. + * Mail byhieg@gmail.com + */ +public class HungrySingleton { + private static final HungrySingleton singleton = new HungrySingleton(); + + private HungrySingleton(){ + + } + +// public static HungrySingleton getSingleton(){ +// return singleton; +// } +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/singleton/SimpleSingleton.java b/src/main/java/cn/byhieg/designpatterntutorial/singleton/SimpleSingleton.java new file mode 100644 index 0000000..fedad66 --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/singleton/SimpleSingleton.java @@ -0,0 +1,26 @@ +package cn.byhieg.designpatterntutorial.singleton; + +import java.io.Serializable; + +/** + * 该类线程不安全,是延迟加载的懒汉模式 + * Created by shiqifeng on 2017/3/14. + * Mail byhieg@gmail.com + */ +public class SimpleSingleton implements Serializable { + + private static SimpleSingleton simpleSingleton; + + private SimpleSingleton(){ + + } + + public static SimpleSingleton getInstance(){ + if (simpleSingleton == null) { + simpleSingleton = new SimpleSingleton(); + } + return simpleSingleton; + } + + +} diff --git a/src/main/java/cn/byhieg/designpatterntutorial/singleton/StaticSingleton.java b/src/main/java/cn/byhieg/designpatterntutorial/singleton/StaticSingleton.java new file mode 100644 index 0000000..8a2ee20 --- /dev/null +++ b/src/main/java/cn/byhieg/designpatterntutorial/singleton/StaticSingleton.java @@ -0,0 +1,20 @@ +package cn.byhieg.designpatterntutorial.singleton; + +/** + * Created by shiqifeng on 2017/3/14. + * Mail byhieg@gmail.com + */ +public class StaticSingleton { + + private StaticSingleton(){ + } + + + public static final StaticSingleton getInstance(){ + return Holder.singleton; + } + + private static class Holder{ + private static final StaticSingleton singleton = new StaticSingleton(); + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/README.md b/src/main/java/cn/byhieg/iotutorial/README.md new file mode 100644 index 0000000..c217dfc --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/README.md @@ -0,0 +1,33 @@ +# Java IO 讲解 + +源码均在src目录下,测试的代码是在test目录下 + +## 字节流 +在该目录下,`bytestreamio` 是 字节流的io类的例子。 +分别有对应输入流的: + +- FileInputStream +- BufferedInputStream +- ByteArrayInputStream + +对应输出流的: + +- FileOutputStream +- BufferedOutputStream +- ByteArrayOutputStream + + +## 字符流 +在该目录下,`charsetstreamio`是 字符流的io类的例子。 + +分别对应输入流的: + +- InputStreamReader +- FileReader +- BufferedWriter + +还有一些涉及到socket,序列化,压缩,管道的类的例子,放到其他的文件夹中。 + +关于IO的一些资料,网上也有很多,就不在总结了,放出一些链接出来: + +[深入分析IO](https://www.ibm.com/developerworks/cn/java/j-lo-javaio/#ibm-pcon) diff --git a/src/main/java/cn/byhieg/iotutorial/bytestreamio/BufferdInputStreamExample.java b/src/main/java/cn/byhieg/iotutorial/bytestreamio/BufferdInputStreamExample.java new file mode 100644 index 0000000..1b05078 --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/bytestreamio/BufferdInputStreamExample.java @@ -0,0 +1,23 @@ +package cn.byhieg.iotutorial.bytestreamio; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class BufferdInputStreamExample { + + public void readFromFile() throws Exception{ + String s = File.separator; + try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:" + s + "read_file.txt"))) { + byte[] bytes = new byte[1024]; + while (bis.read(bytes) != -1) { + String str = new String(bytes); + System.out.println(str); + } + } + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/bytestreamio/BufferdOutputStreamExample.java b/src/main/java/cn/byhieg/iotutorial/bytestreamio/BufferdOutputStreamExample.java new file mode 100644 index 0000000..355d0ad --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/bytestreamio/BufferdOutputStreamExample.java @@ -0,0 +1,24 @@ +package cn.byhieg.iotutorial.bytestreamio; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.nio.charset.Charset; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class BufferdOutputStreamExample { + + public void writeToFile() throws Exception{ + String s = File.separator; + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:" + s + "write_file.txt"))) { + for (int i = 0 ; i < 10000000 ; i++) { + String str = i + ""; + bos.write(str.getBytes(Charset.forName("UTF-8"))); + bos.flush(); + } + } + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/bytestreamio/ByteArrayInputStreamExample.java b/src/main/java/cn/byhieg/iotutorial/bytestreamio/ByteArrayInputStreamExample.java new file mode 100644 index 0000000..621d110 --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/bytestreamio/ByteArrayInputStreamExample.java @@ -0,0 +1,50 @@ +package cn.byhieg.iotutorial.bytestreamio; + +import java.io.ByteArrayInputStream; +import java.io.File; + +/** + * Created by byhieg on 17/2/21. + * Mail to byhieg@gmail.com + */ +public class ByteArrayInputStreamExample { + + public String readFromArray(byte[] bytes) { + StringBuffer sb = new StringBuffer(); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + int tmp; + while ((tmp = bais.read()) != -1) { + sb.append(Integer.toHexString(tmp)); + } + return sb.toString(); + } + + public void readMarkAndReset(byte[] bytes,int mark) { + StringBuffer sb = new StringBuffer(); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + bais.mark(mark); + + bais.skip(mark + 1); + int tmp; + while ((tmp = bais.read()) != -1) { + sb.append(Integer.toHexString(tmp)); + } + + System.out.println("越过标记后的字符串"); + System.out.println(sb.toString()); + + bais.reset(); + sb.setLength(0); + + int m; + while ((m = bais.read()) != -1) { + sb.append(Integer.toHexString(m)); + } + + System.out.println("重置之后的字符串"); + System.out.println(sb.toString()); + } + + + +} diff --git a/src/main/java/cn/byhieg/iotutorial/bytestreamio/ByteArrayOutPutStreamExample.java b/src/main/java/cn/byhieg/iotutorial/bytestreamio/ByteArrayOutPutStreamExample.java new file mode 100644 index 0000000..ba3e5ca --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/bytestreamio/ByteArrayOutPutStreamExample.java @@ -0,0 +1,27 @@ +package cn.byhieg.iotutorial.bytestreamio; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class ByteArrayOutPutStreamExample { + + public void writeToBytes() throws Exception { + try (InputStream is = new FileInputStream("D://read_file.txt")) { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + byte[] bytes = new byte[1024]; + while (is.read(bytes) != -1) { + output.write(bytes); + } + + String data = output.toString("UTF-8"); + System.out.println(data); + + } + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/bytestreamio/FileInputStreamExample.java b/src/main/java/cn/byhieg/iotutorial/bytestreamio/FileInputStreamExample.java new file mode 100644 index 0000000..a8d61f9 --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/bytestreamio/FileInputStreamExample.java @@ -0,0 +1,22 @@ +package cn.byhieg.iotutorial.bytestreamio; + +import java.io.File; +import java.io.FileInputStream; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class FileInputStreamExample { + + public void readFromFile() throws Exception{ + String s = File.separator; + try(FileInputStream fis = new FileInputStream("D:" + s + "read_file.txt")){ + byte[] bytes = new byte[1024]; + while (fis.read(bytes) != -1) { + String str = new String(bytes); + System.out.println(str); + } + } + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/bytestreamio/FileOutputStreamExample.java b/src/main/java/cn/byhieg/iotutorial/bytestreamio/FileOutputStreamExample.java new file mode 100644 index 0000000..4767cf4 --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/bytestreamio/FileOutputStreamExample.java @@ -0,0 +1,23 @@ +package cn.byhieg.iotutorial.bytestreamio; + +import java.io.File; +import java.io.FileOutputStream; +import java.nio.charset.Charset; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class FileOutputStreamExample { + + public void writeToFile() throws Exception{ + String s = File.separator; + try (FileOutputStream fos = new FileOutputStream("D:" + s + "write_file.txt")) { + for (int i = 0 ; i < 10 ; i++) { + String str = i + ""; + fos.write(str.getBytes(Charset.forName("UTF-8"))); + fos.flush(); + } + } + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/charsetstreamio/BufferedReaderExample.java b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/BufferedReaderExample.java new file mode 100644 index 0000000..abe6be2 --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/BufferedReaderExample.java @@ -0,0 +1,21 @@ +package cn.byhieg.iotutorial.charsetstreamio; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class BufferedReaderExample { + + public void readFromFile() throws Exception{ + try(BufferedReader reader = new BufferedReader(new FileReader("D:" + File.separator + "read_file.txt"))){ + String str; + while ((str = reader.readLine()) != null) { + System.out.println(str); + } + } + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/charsetstreamio/BufferedWriterExample.java b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/BufferedWriterExample.java new file mode 100644 index 0000000..1bd2228 --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/BufferedWriterExample.java @@ -0,0 +1,22 @@ +package cn.byhieg.iotutorial.charsetstreamio; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class BufferedWriterExample { + + + public void writeToFile() throws Exception { + try (BufferedWriter bw = new BufferedWriter(new FileWriter("D:" + File.separator + "write_file.txt"))) { + for (int i = 0 ;i < 100000;i++) { + String str = "阿萨建设u无IDask链接"; + bw.write(str); + } + } + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/charsetstreamio/FileReaderExample.java b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/FileReaderExample.java new file mode 100644 index 0000000..3510be4 --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/FileReaderExample.java @@ -0,0 +1,20 @@ +package cn.byhieg.iotutorial.charsetstreamio; + +import java.io.File; +import java.io.FileReader; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class FileReaderExample { + + public void readFromFile() throws Exception{ + try (FileReader reader = new FileReader("D:" + File.separator + "read_file.txt")) { + char[] chars = new char[1024]; + while (reader.read(chars) != -1) { + System.out.println(chars); + } + } + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/charsetstreamio/FileWriterExample.java b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/FileWriterExample.java new file mode 100644 index 0000000..5ae8da8 --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/FileWriterExample.java @@ -0,0 +1,19 @@ +package cn.byhieg.iotutorial.charsetstreamio; + +import java.io.File; +import java.io.FileWriter; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class FileWriterExample { + + public void writeToFile() throws Exception { + try (FileWriter writer = new FileWriter("D:" + File.separator + "write_file.txt")) { + for (int i = 0 ; i< 1000000;i++) { + writer.write("我是byhieg"); + } + } + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/charsetstreamio/InputStreamReaderExample.java b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/InputStreamReaderExample.java new file mode 100644 index 0000000..068d53f --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/InputStreamReaderExample.java @@ -0,0 +1,22 @@ +package cn.byhieg.iotutorial.charsetstreamio; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class InputStreamReaderExample { + + public void readFromFile() throws Exception{ + try (Reader reader = new InputStreamReader(new FileInputStream("D:" + File.separator + "read_file.txt"))) { + char[] chars = new char[1024]; + while (reader.read(chars) != -1){ + System.out.print(new String(chars)); + } + } + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/charsetstreamio/OutputStreamWriterExample.java b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/OutputStreamWriterExample.java new file mode 100644 index 0000000..aa35e77 --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/charsetstreamio/OutputStreamWriterExample.java @@ -0,0 +1,22 @@ +package cn.byhieg.iotutorial.charsetstreamio; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class OutputStreamWriterExample { + + public void writeToFile() throws Exception{ + try (Writer writer = new OutputStreamWriter(new FileOutputStream("D:" + File.separator + "write_file.txt"))) { + for (int i = 0 ; i < 10000;i++) { + writer.write("我是中国人" + ""); + writer.write("\r\n"); + } + } + } +} diff --git a/src/main/java/cn/byhieg/iotutorial/read_file.txt b/src/main/java/cn/byhieg/iotutorial/read_file.txt new file mode 100644 index 0000000..2cb3b74 --- /dev/null +++ b/src/main/java/cn/byhieg/iotutorial/read_file.txt @@ -0,0 +1,5 @@ +I don't know what I do now is right, those are wrong, and when I finally die then I know these. +So what I can do now is to try to do everything well, and then wait to die . +Sometimes I can be very happy to talk to everyone, can be very presumptuous, but no one knows, +it is but very deliberately camouflage, camouflage; I can make him very happy very happy, +but couldn't find the source of happiness, just giggle. \ No newline at end of file diff --git a/src/main/java/cn/byhieg/iotutorial/write_file.txt b/src/main/java/cn/byhieg/iotutorial/write_file.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/cn/byhieg/reflectiontutorial/AnnotationObject.java b/src/main/java/cn/byhieg/reflectiontutorial/AnnotationObject.java new file mode 100644 index 0000000..fdacd5f --- /dev/null +++ b/src/main/java/cn/byhieg/reflectiontutorial/AnnotationObject.java @@ -0,0 +1,21 @@ +package cn.byhieg.reflectiontutorial; + +/** + * Created by byhieg on 17/1/9. + * Mail to byhieg@gmail.com + */ +@MyAnnotation(name="byhieg",value = "hello world") +public class AnnotationObject { + + @MyAnnotation(name="field",value = "变量") + public String field; + + @MyAnnotation(name="method",value = "方法") + public void doSomeThing(){ + System.out.println("做一些事情"); + } + + public void doOtherThing(@MyAnnotation(name="param",value = "参数") String param){ + + } +} diff --git a/src/main/java/cn/byhieg/reflectiontutorial/ArrayObject.java b/src/main/java/cn/byhieg/reflectiontutorial/ArrayObject.java new file mode 100644 index 0000000..dab1baa --- /dev/null +++ b/src/main/java/cn/byhieg/reflectiontutorial/ArrayObject.java @@ -0,0 +1,27 @@ +package cn.byhieg.reflectiontutorial; + +import java.lang.reflect.Array; + +/** + * Created by byhieg on 17/1/10. + * Mail to byhieg@gmail.com + */ +public class ArrayObject { + + public static void main(String[] args) throws Exception{ + int[] intArray = (int[])Array.newInstance(int.class,3); + for (int i = 0 ;i < intArray.length;i++){ + Array.set(intArray,i,i + 2); + } + + for (int i = 0 ; i < intArray.length;i++){ + System.out.println(Array.get(intArray,i)); + } + +// Class clz = int[].class; + Class clz = Class.forName("[I"); + System.out.println(clz.getTypeName()); + System.out.println(clz.getComponentType().getTypeName()); + + } +} diff --git a/src/main/java/cn/byhieg/reflectiontutorial/ExampleObject.java b/src/main/java/cn/byhieg/reflectiontutorial/ExampleObject.java new file mode 100644 index 0000000..b109bb2 --- /dev/null +++ b/src/main/java/cn/byhieg/reflectiontutorial/ExampleObject.java @@ -0,0 +1,61 @@ +package cn.byhieg.reflectiontutorial; + +/** + * Created by shiqifeng on 2017/1/9. + * Mail byhieg@gmail.com + */ +public class ExampleObject extends FatherObject { + public int age = 30; + public String name = "byhieg"; + private Integer score = 60; + + public void printName() { + System.out.println(name); + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getScore() { + return score; + } + + public void setScore(Integer score) { + this.score = score; + } + + public ExampleObject() { + + } + + public ExampleObject(String name) { + + } + + public ExampleObject(int age, Integer score) { + + } + + @Override + public void doSomething() { + super.doSomething(); + } + + @Override + public void run() { + System.out.println("run......"); + } +} diff --git a/src/main/java/cn/byhieg/reflectiontutorial/FatherObject.java b/src/main/java/cn/byhieg/reflectiontutorial/FatherObject.java new file mode 100644 index 0000000..3e933b4 --- /dev/null +++ b/src/main/java/cn/byhieg/reflectiontutorial/FatherObject.java @@ -0,0 +1,14 @@ +package cn.byhieg.reflectiontutorial; + +/** + * Created by shiqifeng on 2017/1/9. + * Mail byhieg@gmail.com + */ +public abstract class FatherObject implements Runnable{ + + + protected String father = ""; + public void doSomething(){ + System.out.println("做事情......"); + } +} diff --git a/src/main/java/cn/byhieg/reflectiontutorial/GenericObject.java b/src/main/java/cn/byhieg/reflectiontutorial/GenericObject.java new file mode 100644 index 0000000..dd74aca --- /dev/null +++ b/src/main/java/cn/byhieg/reflectiontutorial/GenericObject.java @@ -0,0 +1,19 @@ +package cn.byhieg.reflectiontutorial; + +import java.util.List; + +/** + * Created by byhieg on 17/1/9. + * Mail to byhieg@gmail.com + */ +public class GenericObject { + public List lists; + + public List getLists() { + return lists; + } + + public void setLists(List lists) { + this.lists = lists; + } +} diff --git a/src/main/java/cn/byhieg/reflectiontutorial/MyAnnotation.java b/src/main/java/cn/byhieg/reflectiontutorial/MyAnnotation.java new file mode 100644 index 0000000..a66f4fd --- /dev/null +++ b/src/main/java/cn/byhieg/reflectiontutorial/MyAnnotation.java @@ -0,0 +1,18 @@ +package cn.byhieg.reflectiontutorial; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by byhieg on 17/1/9. + * Mail to byhieg@gmail.com + */ + +@Retention(RetentionPolicy.RUNTIME) +public @interface MyAnnotation { + public String name(); + public String value(); + +} diff --git a/src/main/java/cn/byhieg/reflectiontutorial/MyList.java b/src/main/java/cn/byhieg/reflectiontutorial/MyList.java new file mode 100644 index 0000000..884897a --- /dev/null +++ b/src/main/java/cn/byhieg/reflectiontutorial/MyList.java @@ -0,0 +1,31 @@ +package cn.byhieg.reflectiontutorial; + +import java.lang.reflect.Array; +import java.util.List; + +/** + * Created by byhieg on 17/1/9. + * Mail to byhieg@gmail.com + */ +public class MyList { + + public List lists; + public List stringLists ; + + + public List getStringLists() { + return stringLists; + } + + public void setStringLists(List stringLists) { + this.stringLists = stringLists; + } + + public void add(T t){ + lists.add(t); + } + + public T get(int index){ + return lists.get(index); + } +} diff --git a/src/main/java/cn/byhieg/reflectiontutorial/ReadMe.md b/src/main/java/cn/byhieg/reflectiontutorial/ReadMe.md new file mode 100644 index 0000000..e46f8de --- /dev/null +++ b/src/main/java/cn/byhieg/reflectiontutorial/ReadMe.md @@ -0,0 +1,947 @@ + + + +# 详解Java反射各种应用 +Java除了给我们提供在编译期得到类的各种信息之外,还通过反射让我们可以在运行期间得到类的各种信息。通过反射获取类的信息,得到类的信息之后,就可以获取以下相关内容: +- Class对象 +- 构造器 +- 变量 +- 方法 +- 私有变量与私有方法 +- 注解 +- 泛型 +- 数组 + +本文也将从上面几个方面来介绍Java反射。本文涉及的所有代码均在[反射代码](https://github.com/byhieg/JavaTutorial/tree/master/src/main/java/cn/byhieg/reflectiontutorial) +首先放出一个Java类作为反射的研究对象,类的内容如下: +``` +public abstract class FatherObject implements Runnable{ + public void doSomething(){ + System.out.println("做事情......"); + } +} + +public class ExampleObject extends FatherObject{ + public int age = 30; + public String name = "byhieg"; + private Integer score = 60; + + public void printName(){ + System.out.println(name); + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getScore() { + return score; + } + + public void setScore(Integer score) { + this.score = score; + } + + + public ExampleObject(){ + + } + + public ExampleObject(String name){ + + } + + public ExampleObject(int age,Integer score){ + + } + + @Override + public void doSomething() { + super.doSomething(); + } + + @Override + public void run() { + System.out.println("run......"); + } +} + +``` + +## Class对象 +我们应用会用到反射这个知识点,肯定是想要在运行时得到类的信息,根据类的那些信息去做一些特定的操作。那么,首先无疑就是得到类的信息,在JDK中提供了Class对象来保存类的信息。所以,反射的第一步就是得到Class对象。在JDK中提供了两种方式得到Class对象。 +第一种,如果编写代码的时候,就知道Class的名字,可以直接用如下方式得到Class对象: +``` +Class exampleObjectClass = ExampleObject.class; +``` +第二种,如果在编写代码的时候,不知道类的名字,但是在运行时的时候,可以得到一个类名的字符串,可以用如下的方式获取Class对象: +``` +Class exampleObjectClass = Class.forName("cn.byhieg.reflectiontutorial.ExampleObject"); +``` +注意,此方法需要有2个条件,第一,forName中的字符串必须是全限定名,第二,这个Class类必须在classpath的路径下面,因为该方法会抛出`ClassNotFoundException`的异常。 + +获取到这个Class对象之后,就可以得到类的各种信息,开头已经提及了一些信息,下面,说几个没提到的类的信息。 + +### 得到类的名字 +类的名字有两种方式得到,一种是getName(),一种是getSimpleName()。第一种得到的是全限定名,第二种得到的是这个类的名字,不带包名。看下面的例子:Class对象,已经通过上面的代码得到了。 +``` + String fullClassName = exampleObjectClass.getName(); + String simpleClassName = exampleObjectClass.getSimpleName(); + + System.out.println(fullClassName); + System.out.println(simpleClassName); +``` +结果如下: +``` +cn.byhieg.reflectiontutorial.ExampleObject +ExampleObject +``` + +### 得到类的包名、父类和实现的接口 +类的包名和父类,可以通过如下代码得到。 +``` + //得到包信息 + Package aPackage = exampleObjectClass.getPackage(); + System.out.println(aPackage); + + //得到父类 + Class superClass = exampleObjectClass.getSuperclass(); + System.out.println(superClass.getSimpleName()); +``` +结果如下: +``` +package cn.byhieg.reflectiontutorial +FatherObject +``` +很显然,得到父类的返回值也是一个Class对象,那么可以利用这个对象得到父类的一些信息,比如判断父类是不是抽象类 +``` + System.out.println("父类是不是抽象类 " + Modifier.isAbstract(superClass.getModifiers())); +``` +getModifiers可以得到类的修饰符,从而得到类的修饰符,当然,这个getModifiers不仅仅Class对象可以调用,Method对象可以调用。 +可以使用java.lang.reflect.Modifier类中的方法来检查修饰符的类型: +``` +Modifier.isAbstract(int modifiers); +Modifier.isFinal(int modifiers); +Modifier.isInterface(int modifiers); +Modifier.isNative(int modifiers); +Modifier.isPrivate(int modifiers); +Modifier.isProtected(int modifiers); +Modifier.isPublic(int modifiers); +Modifier.isStatic(int modifiers); +Modifier.isStrict(int modifiers); +Modifier.isSynchronized(int modifiers); +Modifier.isTransient(int modifiers); +Modifier.isVolatile(int modifiers); +``` +此外,我们还可以得到父类实现的接口 +``` + //得到接口 + Class[] classes = superClass.getInterfaces(); + System.out.println("父类的接口" + classes[0]); +``` +因为Java类可以实现很多接口,所以用的数组,但在实际使用的时候,需要先判断数组的长度。 +下面,重点讲解上述列出来的内容。 + +## 构造器 +利用Java反射可以得到一个类的构造器,并根据构造器,在运行时动态的创建一个对象。首先,Java通过以下方式获取构造器的实例: +``` + //构造器 + Constructor[] constructors = exampleObjectClass.getConstructors(); + for (Constructor constructor : constructors){ + System.out.println(constructor.toString()); + } +``` +结果如下: +``` +public cn.byhieg.reflectiontutorial.ExampleObject(int,java.lang.Integer) +public cn.byhieg.reflectiontutorial.ExampleObject(java.lang.String) +public cn.byhieg.reflectiontutorial.ExampleObject() +``` +如果,事先知道要访问的构造方法的参数类型,可以利用如下方法获取指定的构造方法,例子如下: +``` + Constructor constructor = exampleObjectClass.getConstructor(String.class); + System.out.println(constructor.toString()); +``` +结果显然是: + +``` +public cn.byhieg.reflectiontutorial.ExampleObject(java.lang.String) +``` +还可以用如下方式得到另一个构造器 +``` + Constructor constructor = exampleObjectClass.getConstructor(int.class,Integer.class); + System.out.println(constructor.toString()); +``` +此外,如果我们不知道构造器的参数,只能得到所有的构造器对象,那么可以用如下方式得到每一个构造器对想的参数: +``` + Constructor[] constructors = exampleObjectClass.getConstructors(); + for (Constructor constructor : constructors){ + Class[] parameterTypes = constructor.getParameterTypes(); + System.out.println("构造器参数如下========================"); + for (Class clz : parameterTypes){ + System.out.println("参数类型 " + clz.toString()); + } + } +``` +结果如下: +``` +构造器参数如下======================== +参数类型 class java.lang.String +构造器参数如下======================== +参数类型 int +参数类型 class java.lang.Integer +``` +这里,可以看出无参构造方法,是不打印出结果的。基本类型的Class对象和引用类型的Class对象toString()方法是不一样的。 +现在,可以根据构造器的各种信息,动态创建一个对象。 +``` + Object object = constructor.newInstance(1,100); + System.out.println(object.toString()); +``` +这个创建对象的方式有2个条件,第一是通过有参构造器创建的,第二,构造器对象必须通过传入参数信息的getConstructor得到。 +第一个条件,对于无参构造方法就可以创建的对象,不需要得到构造器对象,直接Class对象调用newInstance()方法就直接创建对象。 +第二个条件,构造器对象必须通过`exampleObjectClass.getConstructor(String.class);`这种形式得到。如果通过`getConstructors`得到构造器数组,然后调用指定的构造器对象去创建对象在JDK1.8是会错的。但是JDK1.6是正常的。 + +## 变量 +利用Java反射可以在运行时得到一个类的变量信息,并且可以根据上面讲的方式,创建一个对象,设置他的变量值。首先,通过如下方法,得到所有public的变量: +``` + Field[] fields = exampleObjectClass.getFields(); + for (Field field : fields){ + System.out.println("变量为: " + field.toString()); + } +``` +结果如下: + +``` +变量为: public int cn.byhieg.reflectiontutorial.ExampleObject.age +变量为: public java.lang.String cn.byhieg.reflectiontutorial.ExampleObject.name +``` +很显然,得到的都是public的变量,上述的private的变量score,并没有得到。 +和构造器一样的得到方式一样,我们可以指定一个参数名,然后得到指定的变量: +``` + Field field = exampleObjectClass.getField("age"); + System.out.println("变量为:" + field.toString()); +``` +上述的变量的toString方法得到的名字太长,Java对Field类提供了getName的方法,返回类中写的变量名字,上面的代码就可以改成field.getName()。 +反射不仅提供了得到变量的方法,还提供了设置变量值的方式。通过如下方法可以对一个动态生成的类,改变其变量值: +``` + ExampleObject object = ((ExampleObject) constructor1.newInstance("byhieg")); + System.out.println("原先的age是 " + object.age); + field.set(object,10); + System.out.println("更改之后的age是" + object.age); +``` +结果如下: +``` +原先的age是 30 +更改之后的age是10 +``` +根据上面的代码,得到名字为age的Field对象,然后调用该对象的set方法,传入一个对象与要更改的值,就可以改变该对象的值了。注意,此方法不仅仅对成员变量有用,对静态变量也可以。当然,如果是静态变量,传入null,不用传对象,也是可以的。 + + +## 方法 +Java反射给我们除了给我们提供类的变量信息之外,当然也给我们提供了方法的信息,反射可以让我们得到方法名,方法的参数,方法的返回类型,以及调用方法等功能。 +首先,通过如下代码得到方法: +``` + //输出类的public方法 + Method[] methods = exampleObjectClass.getMethods(); + for (Method method : methods){ + System.out.println("method = "+ method.getName()); + } +``` +和获取变量一样似曾相识的代码,这里直接调用了getName,来得到类中写的方法名。写到这里,大家应该自然想到,Java同样提供了根据参数,得到具体的方法。 +``` + Method method = exampleObjectClass.getMethod("setAge",int.class); + System.out.println(method.getName()); +``` +这里与得到变量不同的是,getMethod方法还需要传入参数的类型信息,反射提供获取方法参数以及返回类型的方法,得到方法参数的例子如下: +``` + Method method = exampleObjectClass.getMethod("setAge",int.class); + System.out.println(method.getName()); + for (Class clz : method.getParameterTypes()){ + System.out.println("方法的参数" + clz.getName()); + } +``` +结果如下: +``` +setAge +方法的参数int +``` +得到方法返回类型的例子如下: +``` +System.out.println(method.getReturnType().getName()); +``` +结果如下: +``` +void +``` +此外,Java反射支持通过invoke调用得到的方法。例子如下: +``` +method.invoke(exampleObjectClass.newInstance(),1); +``` +invoke第一个参数是这个对象,第二个参数是变长数组,传入该方法的参数。和Field对象同样,对于静态方法同样,可以传入null,调用静态方法。 +## 私有变量与私有方法 +上面的方法只能得到public方法和变量,无法得到非public修饰的方法和变量,Java提供了额外的方法来得到非public变量与方法。即通过`getDeclaredFields`与`getDeclaredMethods`方法得到私有的变量与方法,同样也支持用`getDeclaredField(变量名)`与` getDeclaredMethod(方法名)`的形式得到指定的变量名与方法名。但是这样得到的Field对象与Method对象无法直接运用,必须让这些对象调用setAccessible(true),才能正常运用。之后的方式就可上面讲的一样了。 + +## 注解 +先写一个包含注解的类: +``` +MyAnnotation(name="byhieg",value = "hello world") +public class AnnotationObject { + + @MyAnnotation(name="field",value = "变量") + public String field; + + @MyAnnotation(name="method",value = "方法") + public void doSomeThing(){ + System.out.println("做一些事情"); + } + + public void doOtherThing(@MyAnnotation(name="param",value = "参数") String param){ + + } +} + +@Retention(RetentionPolicy.RUNTIME) +public @interface MyAnnotation { + public String name(); + public String value(); + +} +``` +Java给我们提供了在运行时获取类的注解信息,可以得到类注解,方法注解,参数注解,变量注解。 +与上面获取方式一样,Java提供了2种获取方式,一种是获取全部的注解,返回一个数组,第二种是指定得到指定的注解。 +我们以一个类注解为例,讲解以下这两种获取方式。 +``` + Class clz = AnnotationObject.class; + Annotation[] annotations = clz.getAnnotations(); + Annotation annotation = clz.getAnnotation(AnnotationObject.class); +``` +然后,就可以根据得到的注解进行后续的处理,下面是一个处理的例子: +``` + for (Annotation annotation : annotations){ + if (annotation instanceof MyAnnotation){ + MyAnnotation myAnnotation = (MyAnnotation)annotation; + System.out.println("name: " + myAnnotation.name()); + System.out.println("value:" + myAnnotation.value()); + } + } +``` +上面的类注解使用Class对象调用`getAnnotations`得到的,方法注解和变量注解是一样的,分别用method对象与field对象调用`getDeclaredAnnotations`得到注解,没什么多说的。例子看[反射代码](https://github.com/byhieg/JavaTutorial/tree/master/src/main/java/cn/byhieg/reflectiontutorial) +参数注解是比较麻烦的一项,获取方式比较得到,第一步,先取得method对象,调用`getParameterAnnotations`,但是这个返回值是一个二维数组,因为method对象有很多参数,每个参数有可能有很多注解。例子如下: +``` + Method method1 = clz.getMethod("doOtherThing",String.class); + Annotation[][] annotationInParam = method1.getParameterAnnotations(); + Class[] params = method1.getParameterTypes(); + int i = 0; + for (Annotation[] annotations: annotationInParam){ + Class para = params[i++]; + for (Annotation annotation : annotations){ + if(annotation instanceof MyAnnotation){ + MyAnnotation myAnnotation = (MyAnnotation) annotation; + System.out.println("param: " + para.getName()); + System.out.println("name : " + myAnnotation.name()); + System.out.println("value :" + myAnnotation.value()); + } + + } + } +``` +## 泛型 +因为Java泛型是通过擦除来实现的,很难直接得到泛型具体的参数化类型的信息,但是我们可以通过一种间接的形式利用反射得到泛型信息。比如下面这个类: +``` +public class GenericObject { + public List lists; + + public List getLists() { + return lists; + } + + public void setLists(List lists) { + this.lists = lists; + } +} +``` +如果一个方法返回一个泛型类,我们可以通过method对象去调用`getGenericReturnType`来得到这个泛型类具体的参数化类型是什么。看下面的代码: +``` + Class clz = GenericObject.class; + Method method = clz.getMethod("getLists"); + Type genericType = method.getGenericReturnType(); + if(genericType instanceof ParameterizedType){ + ParameterizedType parameterizedType = ((ParameterizedType) genericType); + Type[] types = parameterizedType.getActualTypeArguments(); + for (Type type : types){ + Class actualClz = ((Class) type); + System.out.println("参数化类型为 : " + actualClz); + } + } +``` +结果如下: +``` +参数化类型为 : class java.lang.String +``` +步骤有点繁琐,下面一步步解释: +1. 反射得到返回类型为泛型类的方法 +2. 调用`getGenericReturnType`得到方法返回类型中的参数化类型 +3. 判断该type对象能不能向下转型为`ParameterizedType` +4. 转型成功,调用`getActualTypeArguments`得到参数化类型的数组,因为有的泛型类,不只只有一个参数化类型如Map +5. 取出数组中的每一个的值,转型为Class对象输出。 + +看结果确实得到了泛型的具体的信息。 +如果没有一个方法返回泛型类型,那么我们也可以通过方法的参数为泛型类,来得到泛型的参数化类型,如上面类中的setLists方法。例子如下: +``` + Method setMethod = clz.getMethod("setLists", List.class); + Type[] genericParameterTypes = setMethod.getGenericParameterTypes(); + for (Type genericParameterType: genericParameterTypes){ + System.out.println("GenericParameterTypes为 : " + genericParameterType.getTypeName()); + if(genericParameterType instanceof ParameterizedType){ + ParameterizedType parameterizedType = ((ParameterizedType) genericParameterType); + System.out.println("ParameterizedType为 :" + parameterizedType.getTypeName()); + Type types[] = parameterizedType.getActualTypeArguments(); + for (Type type : types){ + System.out.println("参数化类型为 : " + ((Class) type).getName()); + } + } + + } +``` +执行的结果如下: +``` +GenericParameterTypes为 : java.util.List +ParameterizedType为 :java.util.List +参数化类型为 : java.lang.String +``` +因为方法的参数为泛型类型的可能不止一个,所以通过`getGenericParameterTypes`得到是一个数组,我们需要确定每一个元素,是否是具有参数化类型。后续的步骤与上面类似,就不多说了。 +如果连方法参数都不带泛型类,那么只剩下最后一种情况,通过变量类型,即用Field类。例子如下: +``` + Field field = clz.getField("lists"); + Type type = field.getGenericType(); + if (type instanceof ParameterizedType){ + ParameterizedType parameterizedType = ((ParameterizedType) type); + Type [] types = parameterizedType.getActualTypeArguments(); + for (Type type1 : types) { + System.out.println("参数化类型 : " + ((Class) type1).getTypeName()); + } + } +``` +原理和上面的一样,只不过Type对象是通过`field.getGenericType()`,剩下的操作类似就不多说了。 +关于通过反射获取泛型的参数化类型的信息的介绍就到此为止。 + +## 数组 +Java反射可以对数组进行操作,包括创建一个数组,访问数组中的值,以及得到一个数组的Class对象。 +下面,先说简单的,创建数组以及访问数组中的值:在反射中使用Array这个类,是reflect包下面的。 +``` + //创建一个int类型的数组,长度为3 + int[] intArray = (int[])Array.newInstance(int.class,3); + //通过反射的形式,给数组赋值 + for (int i = 0 ;i < intArray.length;i++){ + Array.set(intArray,i,i + 2); + } +//通过反射的形式,得到数组中的值 + for (int i = 0 ; i < intArray.length;i++){ + System.out.println(Array.get(intArray,i)); + } +``` +上述就是创建数组,访问数组中的值利用反射方式。 +对于得到一个数组的Class对象,简单的可以用`int[].class`,或者利用Class.forName的形式得到,写法比较奇怪: +``` + Class clz = Class.forName("[I"); + System.out.println(clz.getTypeName()); +``` +结果为: +``` +int[] +``` +这个forName中的字符串,`[`表示是数组,`I`表示是int,float就是`F`,double就是`D`等等,如果要得到一个普通对象的数组,则用下面的形式: +``` + Class stringClz = Class.forName("[Ljava.lang.String;"); +``` +`[`表示是数组,`L`的右边是类名,类型的右边是一个`;`; +这种方式获取数组的Class对象实在是太繁琐了。 +在得到数组的Class对象之后,就可以调用他的一些独特的方法,比如调用`getComponentType`来得到数组成员的类型信息,如int数组就是成员类型就是int。 +``` +System.out.println(clz.getComponentType().getTypeName()); +``` +结果为`int` + +## 总结 +这次,关于反射的各种应用就到此为止,后续可能会有深入的知识讲解。具体的代码可以去看[反射代码](https://github.com/byhieg/JavaTutorial/tree/master/src/main/java/cn/byhieg/reflectiontutorial) +在src包里面是各种类,在test类里是对这些类的访问。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +详解Java反射各种应用 + +Java除了给我们提供在编译期得到类的各种信息之外,还通过反射让我们可以在运行期间得到类的各种信息。通过反射获取类的信息,得到类的信息之后,就可以获取以下相关内容: + +Class对象 +构造器 +变量 +方法 +私有变量与私有方法 +注解 +泛型 +数组 +本文也将从上面几个方面来介绍Java反射。本文涉及的所有代码均在反射代码 +首先放出一个Java类作为反射的研究对象,类的内容如下: + +public abstract class FatherObject implements Runnable{ + public void doSomething(){ + System.out.println("做事情......"); + } +} + +public class ExampleObject extends FatherObject{ + public int age = 30; + public String name = "byhieg"; + private Integer score = 60; + + public void printName(){ + System.out.println(name); + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getScore() { + return score; + } + + public void setScore(Integer score) { + this.score = score; + } + + + public ExampleObject(){ + + } + + public ExampleObject(String name){ + + } + + public ExampleObject(int age,Integer score){ + + } + + @Override + public void doSomething() { + super.doSomething(); + } + + @Override + public void run() { + System.out.println("run......"); + } +} + +Class对象 + +我们应用会用到反射这个知识点,肯定是想要在运行时得到类的信息,根据类的那些信息去做一些特定的操作。那么,首先无疑就是得到类的信息,在JDK中提供了Class对象来保存类的信息。所以,反射的第一步就是得到Class对象。在JDK中提供了两种方式得到Class对象。 +第一种,如果编写代码的时候,就知道Class的名字,可以直接用如下方式得到Class对象: + +Class exampleObjectClass = ExampleObject.class; +第二种,如果在编写代码的时候,不知道类的名字,但是在运行时的时候,可以得到一个类名的字符串,可以用如下的方式获取Class对象: + +Class exampleObjectClass = Class.forName("cn.byhieg.reflectiontutorial.ExampleObject"); +注意,此方法需要有2个条件,第一,forName中的字符串必须是全限定名,第二,这个Class类必须在classpath的路径下面,因为该方法会抛出ClassNotFoundException的异常。 + +获取到这个Class对象之后,就可以得到类的各种信息,开头已经提及了一些信息,下面,说几个没提到的类的信息。 + +得到类的名字 + +类的名字有两种方式得到,一种是getName(),一种是getSimpleName()。第一种得到的是全限定名,第二种得到的是这个类的名字,不带包名。看下面的例子:Class对象,已经通过上面的代码得到了。 + + String fullClassName = exampleObjectClass.getName(); + String simpleClassName = exampleObjectClass.getSimpleName(); + + System.out.println(fullClassName); + System.out.println(simpleClassName); +结果如下: + +cn.byhieg.reflectiontutorial.ExampleObject +ExampleObject +得到类的包名、父类和实现的接口 + +类的包名和父类,可以通过如下代码得到。 + + //得到包信息 + Package aPackage = exampleObjectClass.getPackage(); + System.out.println(aPackage); + + //得到父类 + Class superClass = exampleObjectClass.getSuperclass(); + System.out.println(superClass.getSimpleName()); +结果如下: + +package cn.byhieg.reflectiontutorial +FatherObject +很显然,得到父类的返回值也是一个Class对象,那么可以利用这个对象得到父类的一些信息,比如判断父类是不是抽象类 + + System.out.println("父类是不是抽象类 " + Modifier.isAbstract(superClass.getModifiers())); +getModifiers可以得到类的修饰符,从而得到类的修饰符,当然,这个getModifiers不仅仅Class对象可以调用,Method对象可以调用。 +可以使用java.lang.reflect.Modifier类中的方法来检查修饰符的类型: + +Modifier.isAbstract(int modifiers); +Modifier.isFinal(int modifiers); +Modifier.isInterface(int modifiers); +Modifier.isNative(int modifiers); +Modifier.isPrivate(int modifiers); +Modifier.isProtected(int modifiers); +Modifier.isPublic(int modifiers); +Modifier.isStatic(int modifiers); +Modifier.isStrict(int modifiers); +Modifier.isSynchronized(int modifiers); +Modifier.isTransient(int modifiers); +Modifier.isVolatile(int modifiers); +此外,我们还可以得到父类实现的接口 + + //得到接口 + Class[] classes = superClass.getInterfaces(); + System.out.println("父类的接口" + classes[0]); +因为Java类可以实现很多接口,所以用的数组,但在实际使用的时候,需要先判断数组的长度。 +下面,重点讲解上述列出来的内容。 + +构造器 + +利用Java反射可以得到一个类的构造器,并根据构造器,在运行时动态的创建一个对象。首先,Java通过以下方式获取构造器的实例: + + //构造器 + Constructor[] constructors = exampleObjectClass.getConstructors(); + for (Constructor constructor : constructors){ + System.out.println(constructor.toString()); + } +结果如下: + +public cn.byhieg.reflectiontutorial.ExampleObject(int,java.lang.Integer) +public cn.byhieg.reflectiontutorial.ExampleObject(java.lang.String) +public cn.byhieg.reflectiontutorial.ExampleObject() +如果,事先知道要访问的构造方法的参数类型,可以利用如下方法获取指定的构造方法,例子如下: + + Constructor constructor = exampleObjectClass.getConstructor(String.class); + System.out.println(constructor.toString()); +结果显然是: + +public cn.byhieg.reflectiontutorial.ExampleObject(java.lang.String) +还可以用如下方式得到另一个构造器 + + Constructor constructor = exampleObjectClass.getConstructor(int.class,Integer.class); + System.out.println(constructor.toString()); +此外,如果我们不知道构造器的参数,只能得到所有的构造器对象,那么可以用如下方式得到每一个构造器对想的参数: + + Constructor[] constructors = exampleObjectClass.getConstructors(); + for (Constructor constructor : constructors){ + Class[] parameterTypes = constructor.getParameterTypes(); + System.out.println("构造器参数如下========================"); + for (Class clz : parameterTypes){ + System.out.println("参数类型 " + clz.toString()); + } + } +结果如下: + +构造器参数如下======================== +参数类型 class java.lang.String +构造器参数如下======================== +参数类型 int +参数类型 class java.lang.Integer +这里,可以看出无参构造方法,是不打印出结果的。基本类型的Class对象和引用类型的Class对象toString()方法是不一样的。 +现在,可以根据构造器的各种信息,动态创建一个对象。 + + Object object = constructor.newInstance(1,100); + System.out.println(object.toString()); +这个创建对象的方式有2个条件,第一是通过有参构造器创建的,第二,构造器对象必须通过传入参数信息的getConstructor得到。 +第一个条件,对于无参构造方法就可以创建的对象,不需要得到构造器对象,直接Class对象调用newInstance()方法就直接创建对象。 +第二个条件,构造器对象必须通过exampleObjectClass.getConstructor(String.class);这种形式得到。如果通过getConstructors得到构造器数组,然后调用指定的构造器对象去创建对象在JDK1.8是会错的。但是JDK1.6是正常的。 + +变量 + +利用Java反射可以在运行时得到一个类的变量信息,并且可以根据上面讲的方式,创建一个对象,设置他的变量值。首先,通过如下方法,得到所有public的变量: + + Field[] fields = exampleObjectClass.getFields(); + for (Field field : fields){ + System.out.println("变量为: " + field.toString()); + } +结果如下: + +变量为: public int cn.byhieg.reflectiontutorial.ExampleObject.age +变量为: public java.lang.String cn.byhieg.reflectiontutorial.ExampleObject.name +很显然,得到的都是public的变量,上述的private的变量score,并没有得到。 +和构造器一样的得到方式一样,我们可以指定一个参数名,然后得到指定的变量: + + Field field = exampleObjectClass.getField("age"); + System.out.println("变量为:" + field.toString()); +上述的变量的toString方法得到的名字太长,Java对Field类提供了getName的方法,返回类中写的变量名字,上面的代码就可以改成field.getName()。 +反射不仅提供了得到变量的方法,还提供了设置变量值的方式。通过如下方法可以对一个动态生成的类,改变其变量值: + + ExampleObject object = ((ExampleObject) constructor1.newInstance("byhieg")); + System.out.println("原先的age是 " + object.age); + field.set(object,10); + System.out.println("更改之后的age是" + object.age); +结果如下: + +原先的age是 30 +更改之后的age是10 +根据上面的代码,得到名字为age的Field对象,然后调用该对象的set方法,传入一个对象与要更改的值,就可以改变该对象的值了。注意,此方法不仅仅对成员变量有用,对静态变量也可以。当然,如果是静态变量,传入null,不用传对象,也是可以的。 + +方法 + +Java反射给我们除了给我们提供类的变量信息之外,当然也给我们提供了方法的信息,反射可以让我们得到方法名,方法的参数,方法的返回类型,以及调用方法等功能。 +首先,通过如下代码得到方法: + + //输出类的public方法 + Method[] methods = exampleObjectClass.getMethods(); + for (Method method : methods){ + System.out.println("method = "+ method.getName()); + } +和获取变量一样似曾相识的代码,这里直接调用了getName,来得到类中写的方法名。写到这里,大家应该自然想到,Java同样提供了根据参数,得到具体的方法。 + + Method method = exampleObjectClass.getMethod("setAge",int.class); + System.out.println(method.getName()); +这里与得到变量不同的是,getMethod方法还需要传入参数的类型信息,反射提供获取方法参数以及返回类型的方法,得到方法参数的例子如下: + + Method method = exampleObjectClass.getMethod("setAge",int.class); + System.out.println(method.getName()); + for (Class clz : method.getParameterTypes()){ + System.out.println("方法的参数" + clz.getName()); + } +结果如下: + +setAge +方法的参数int +得到方法返回类型的例子如下: + +System.out.println(method.getReturnType().getName()); +结果如下: + +void +此外,Java反射支持通过invoke调用得到的方法。例子如下: + +method.invoke(exampleObjectClass.newInstance(),1); +invoke第一个参数是这个对象,第二个参数是变长数组,传入该方法的参数。和Field对象同样,对于静态方法同样,可以传入null,调用静态方法。 + +私有变量与私有方法 + +上面的方法只能得到public方法和变量,无法得到非public修饰的方法和变量,Java提供了额外的方法来得到非public变量与方法。即通过getDeclaredFields与getDeclaredMethods方法得到私有的变量与方法,同样也支持用getDeclaredField(变量名)与getDeclaredMethod(方法名)的形式得到指定的变量名与方法名。但是这样得到的Field对象与Method对象无法直接运用,必须让这些对象调用setAccessible(true),才能正常运用。之后的方式就可上面讲的一样了。 + +注解 + +先写一个包含注解的类: + +MyAnnotation(name="byhieg",value = "hello world") +public class AnnotationObject { + + @MyAnnotation(name="field",value = "变量") + public String field; + + @MyAnnotation(name="method",value = "方法") + public void doSomeThing(){ + System.out.println("做一些事情"); + } + + public void doOtherThing(@MyAnnotation(name="param",value = "参数") String param){ + + } +} + +@Retention(RetentionPolicy.RUNTIME) +public @interface MyAnnotation { + public String name(); + public String value(); + +} +Java给我们提供了在运行时获取类的注解信息,可以得到类注解,方法注解,参数注解,变量注解。 +与上面获取方式一样,Java提供了2种获取方式,一种是获取全部的注解,返回一个数组,第二种是指定得到指定的注解。 +我们以一个类注解为例,讲解以下这两种获取方式。 + + Class clz = AnnotationObject.class; + Annotation[] annotations = clz.getAnnotations(); + Annotation annotation = clz.getAnnotation(AnnotationObject.class); +然后,就可以根据得到的注解进行后续的处理,下面是一个处理的例子: + + for (Annotation annotation : annotations){ + if (annotation instanceof MyAnnotation){ + MyAnnotation myAnnotation = (MyAnnotation)annotation; + System.out.println("name: " + myAnnotation.name()); + System.out.println("value:" + myAnnotation.value()); + } + } +上面的类注解使用Class对象调用getAnnotations得到的,方法注解和变量注解是一样的,分别用method对象与field对象调用getDeclaredAnnotations得到注解,没什么多说的。例子看反射代码 +参数注解是比较麻烦的一项,获取方式比较得到,第一步,先取得method对象,调用getParameterAnnotations,但是这个返回值是一个二维数组,因为method对象有很多参数,每个参数有可能有很多注解。例子如下: + + Method method1 = clz.getMethod("doOtherThing",String.class); + Annotation[][] annotationInParam = method1.getParameterAnnotations(); + Class[] params = method1.getParameterTypes(); + int i = 0; + for (Annotation[] annotations: annotationInParam){ + Class para = params[i++]; + for (Annotation annotation : annotations){ + if(annotation instanceof MyAnnotation){ + MyAnnotation myAnnotation = (MyAnnotation) annotation; + System.out.println("param: " + para.getName()); + System.out.println("name : " + myAnnotation.name()); + System.out.println("value :" + myAnnotation.value()); + } + + } + } +泛型 + +因为Java泛型是通过擦除来实现的,很难直接得到泛型具体的参数化类型的信息,但是我们可以通过一种间接的形式利用反射得到泛型信息。比如下面这个类: + +public class GenericObject { + public List lists; + + public List getLists() { + return lists; + } + + public void setLists(List lists) { + this.lists = lists; + } +} +如果一个方法返回一个泛型类,我们可以通过method对象去调用getGenericReturnType来得到这个泛型类具体的参数化类型是什么。看下面的代码: + + Class clz = GenericObject.class; + Method method = clz.getMethod("getLists"); + Type genericType = method.getGenericReturnType(); + if(genericType instanceof ParameterizedType){ + ParameterizedType parameterizedType = ((ParameterizedType) genericType); + Type[] types = parameterizedType.getActualTypeArguments(); + for (Type type : types){ + Class actualClz = ((Class) type); + System.out.println("参数化类型为 : " + actualClz); + } + } +结果如下: + +参数化类型为 : class java.lang.String +步骤有点繁琐,下面一步步解释: + +反射得到返回类型为泛型类的方法 +调用getGenericReturnType得到方法返回类型中的参数化类型 +判断该type对象能不能向下转型为ParameterizedType +转型成功,调用getActualTypeArguments得到参数化类型的数组,因为有的泛型类,不只只有一个参数化类型如Map +取出数组中的每一个的值,转型为Class对象输出。 +看结果确实得到了泛型的具体的信息。 +如果没有一个方法返回泛型类型,那么我们也可以通过方法的参数为泛型类,来得到泛型的参数化类型,如上面类中的setLists方法。例子如下: + + Method setMethod = clz.getMethod("setLists", List.class); + Type[] genericParameterTypes = setMethod.getGenericParameterTypes(); + for (Type genericParameterType: genericParameterTypes){ + System.out.println("GenericParameterTypes为 : " + genericParameterType.getTypeName()); + if(genericParameterType instanceof ParameterizedType){ + ParameterizedType parameterizedType = ((ParameterizedType) genericParameterType); + System.out.println("ParameterizedType为 :" + parameterizedType.getTypeName()); + Type types[] = parameterizedType.getActualTypeArguments(); + for (Type type : types){ + System.out.println("参数化类型为 : " + ((Class) type).getName()); + } + } + + } +执行的结果如下: + +GenericParameterTypes为 : java.util.List +ParameterizedType为 :java.util.List +参数化类型为 : java.lang.String +因为方法的参数为泛型类型的可能不止一个,所以通过getGenericParameterTypes得到是一个数组,我们需要确定每一个元素,是否是具有参数化类型。后续的步骤与上面类似,就不多说了。 +如果连方法参数都不带泛型类,那么只剩下最后一种情况,通过变量类型,即用Field类。例子如下: + + Field field = clz.getField("lists"); + Type type = field.getGenericType(); + if (type instanceof ParameterizedType){ + ParameterizedType parameterizedType = ((ParameterizedType) type); + Type [] types = parameterizedType.getActualTypeArguments(); + for (Type type1 : types) { + System.out.println("参数化类型 : " + ((Class) type1).getTypeName()); + } + } +原理和上面的一样,只不过Type对象是通过field.getGenericType(),剩下的操作类似就不多说了。 +关于通过反射获取泛型的参数化类型的信息的介绍就到此为止。 + +数组 + +Java反射可以对数组进行操作,包括创建一个数组,访问数组中的值,以及得到一个数组的Class对象。 +下面,先说简单的,创建数组以及访问数组中的值:在反射中使用Array这个类,是reflect包下面的。 + + //创建一个int类型的数组,长度为3 + int[] intArray = (int[])Array.newInstance(int.class,3); + //通过反射的形式,给数组赋值 + for (int i = 0 ;i < intArray.length;i++){ + Array.set(intArray,i,i + 2); + } +//通过反射的形式,得到数组中的值 + for (int i = 0 ; i < intArray.length;i++){ + System.out.println(Array.get(intArray,i)); + } +上述就是创建数组,访问数组中的值利用反射方式。 +对于得到一个数组的Class对象,简单的可以用int[].class,或者利用Class.forName的形式得到,写法比较奇怪: + + Class clz = Class.forName("[I"); + System.out.println(clz.getTypeName()); +结果为: + +int[] +这个forName中的字符串,[表示是数组,I表示是int,float就是F,double就是D等等,如果要得到一个普通对象的数组,则用下面的形式: + + Class stringClz = Class.forName("[Ljava.lang.String;"); +[表示是数组,L的右边是类名,类型的右边是一个;; +这种方式获取数组的Class对象实在是太繁琐了。 +在得到数组的Class对象之后,就可以调用他的一些独特的方法,比如调用getComponentType来得到数组成员的类型信息,如int数组就是成员类型就是int。 + +System.out.println(clz.getComponentType().getTypeName()); +结果为int + +总结 + +这次,关于反射的各种应用就到此为止,后续可能会有深入的知识讲解。具体的代码可以去看反射代码 +在src包里面是各种类,在test类里是对这些类的访问。 diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/CommonUtils.java b/src/main/java/cn/byhieg/threadtutorial/char02/CommonUtils.java new file mode 100644 index 0000000..394b0dd --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/CommonUtils.java @@ -0,0 +1,14 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class CommonUtils { + + public static long beginTime1; + public static long endTime1; + + public static long beginTime2; + public static long endTime2; +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/DeadLock.java b/src/main/java/cn/byhieg/threadtutorial/char02/DeadLock.java new file mode 100644 index 0000000..547e9a7 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/DeadLock.java @@ -0,0 +1,47 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/4. + * Mail byhieg@gmail.com + */ +public class DeadLock implements Runnable{ + + public String username; + public Object lock1 = new Object(); + public Object lock2 = new Object(); + + public void setFlag(String username){ + this.username = username; + } + public void run() { + if ("a".equals(username)){ + synchronized (lock1){ + try{ + System.out.println("username = " + username); + Thread.sleep(3000); + }catch (InterruptedException e){ + e.printStackTrace(); + } + + synchronized (lock2){ + System.out.println("按照lock1 - > lock2代码顺序执行"); + } + } + } + + if ("b".equals(username)){ + synchronized (lock2){ + try{ + System.out.println("username = " + username); + Thread.sleep(3000); + }catch (InterruptedException e){ + e.printStackTrace(); + } + + synchronized (lock1){ + System.out.println("按 lock2 - > lock1代码顺序执行"); + } + } + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/DoubleSynThreadA.java b/src/main/java/cn/byhieg/threadtutorial/char02/DoubleSynThreadA.java new file mode 100644 index 0000000..d477634 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/DoubleSynThreadA.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class DoubleSynThreadA extends Thread{ + private ObjectService objectService; + + public DoubleSynThreadA(ObjectService objectService){ + this.objectService = objectService; + } + + @Override + public void run() { + super.run(); + objectService.serviceMethodA(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/DoubleSynThreadB.java b/src/main/java/cn/byhieg/threadtutorial/char02/DoubleSynThreadB.java new file mode 100644 index 0000000..15a2061 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/DoubleSynThreadB.java @@ -0,0 +1,21 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class DoubleSynThreadB extends Thread{ + + private ObjectService objectService; + + public DoubleSynThreadB(ObjectService objectService){ + this.objectService = objectService; + + } + + @Override + public void run() { + super.run(); + objectService.serviceMethodB(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/ExceptionService.java b/src/main/java/cn/byhieg/threadtutorial/char02/ExceptionService.java new file mode 100644 index 0000000..4601da7 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/ExceptionService.java @@ -0,0 +1,29 @@ +package cn.byhieg.threadtutorial.char02; + +import java.io.*; + +/** + * Created by byhieg on 17/1/5. + * Mail to byhieg@gmail.com + */ +public class ExceptionService { + + synchronized public void getFile(){ + System.out.println("begin " + System.currentTimeMillis() + " " + Thread.currentThread().getName()); + File file = new File("111"); + try { + Thread.sleep(1000 * 1); + System.out.println(5 / 0); + InputStream in = new FileInputStream(file); + System.out.println("end" + System.currentTimeMillis() + " " + Thread.currentThread().getName()); + + } catch (FileNotFoundException | InterruptedException e) { + try { + Thread.sleep(1000); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + System.out.println("end Catch" + System.currentTimeMillis() + " " + Thread.currentThread().getName()); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/FatherSynService.java b/src/main/java/cn/byhieg/threadtutorial/char02/FatherSynService.java new file mode 100644 index 0000000..e916288 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/FatherSynService.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class FatherSynService { + + public int i = 10; + synchronized public void operateIMainMethod(){ + try{ + i--; + System.out.println("main print i=" +i); + Thread.sleep(100); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/HalfSynTask.java b/src/main/java/cn/byhieg/threadtutorial/char02/HalfSynTask.java new file mode 100644 index 0000000..d73cf45 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/HalfSynTask.java @@ -0,0 +1,36 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class HalfSynTask { + + public void doLongTimeTask(){ + for(int i = 0 ;i < 4;i++){ + System.out.println("nosynchronized threadName=" + Thread.currentThread().getName() + " i=" + (i + 1)); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + System.out.println(""); + + synchronized (this){ + for (int i = 0 ; i < 4;i++){ + System.out.println("synchronized threadName=" +Thread.currentThread().getName() + " i=" + (i + 1)); + } + } + + for (int i = 1000 ; i < 1005;i ++){ + System.out.println("after synchronize =" + Thread.currentThread().getName() + " i=" + (i + 1)); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/HalfTaskThread.java b/src/main/java/cn/byhieg/threadtutorial/char02/HalfTaskThread.java new file mode 100644 index 0000000..6bc48ec --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/HalfTaskThread.java @@ -0,0 +1,20 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class HalfTaskThread extends Thread{ + + private HalfSynTask task; + + public HalfTaskThread(HalfSynTask task){ + this.task = task; + } + + @Override + public void run() { + super.run(); + task.doLongTimeTask(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/HasSelfPrivateNum.java b/src/main/java/cn/byhieg/threadtutorial/char02/HasSelfPrivateNum.java new file mode 100644 index 0000000..a3ee818 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/HasSelfPrivateNum.java @@ -0,0 +1,26 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/1. + * Mail to byhieg@gmail.com + */ +public class HasSelfPrivateNum { + + private int num = 0; + + public void addI(String username){ + try{ + if (username.equals("a")){ + num = 100; + System.out.println("a set over!"); + Thread.sleep(2000); + }else { + num = 200; + System.out.println("b set over!"); + } + System.out.println(username + " num=" + num); + }catch (Exception e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/ListThread.java b/src/main/java/cn/byhieg/threadtutorial/char02/ListThread.java new file mode 100644 index 0000000..8369e84 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/ListThread.java @@ -0,0 +1,23 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class ListThread extends Thread{ + + private MyOneList list; + private String str; + + public ListThread(MyOneList list,String str){ + this.list = list; + this.str = str; + } + + @Override + public void run() { + super.run(); + MyOneListService service = new MyOneListService(); + service.addServiceMethod(list,str); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/LongTimeServiceThreadA.java b/src/main/java/cn/byhieg/threadtutorial/char02/LongTimeServiceThreadA.java new file mode 100644 index 0000000..6184b21 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/LongTimeServiceThreadA.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class LongTimeServiceThreadA extends Thread{ + + private LongTimeTask task; + public LongTimeServiceThreadA(LongTimeTask task){ + super(); + this.task = task; + } + + @Override + public void run() { + super.run(); + CommonUtils.beginTime1 = System.currentTimeMillis(); + task.doLongTimeTask(); + CommonUtils.endTime1 = System.currentTimeMillis(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/LongTimeServiceThreadB.java b/src/main/java/cn/byhieg/threadtutorial/char02/LongTimeServiceThreadB.java new file mode 100644 index 0000000..a87f277 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/LongTimeServiceThreadB.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class LongTimeServiceThreadB extends Thread{ + + private LongTimeTask task; + public LongTimeServiceThreadB(LongTimeTask task){ + super(); + this.task = task; + } + + @Override + public void run() { + super.run(); + CommonUtils.beginTime2 = System.currentTimeMillis(); + task.doLongTimeTask(); + CommonUtils.endTime2 = System.currentTimeMillis(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/LongTimeTask.java b/src/main/java/cn/byhieg/threadtutorial/char02/LongTimeTask.java new file mode 100644 index 0000000..3473c74 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/LongTimeTask.java @@ -0,0 +1,30 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class LongTimeTask { + private String getData1; + private String getData2; + + public void doLongTimeTask(){ + try{ + System.out.println("begin task"); + Thread.sleep(3000); + String privateGetData1 = "长时间处理任务后从远程返回的值 1 threadName=" + Thread.currentThread().getName(); + String privateGetData2 = "长时间处理任务后从远程返回的值 2 threadName=" + Thread.currentThread().getName(); + + synchronized (this){ + getData1 = privateGetData1; + getData2 = privateGetData2; + } + + System.out.println(getData1); + System.out.println(getData2); + System.out.println("end task"); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/MyObject.java b/src/main/java/cn/byhieg/threadtutorial/char02/MyObject.java new file mode 100644 index 0000000..c6276e3 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/MyObject.java @@ -0,0 +1,32 @@ +package cn.byhieg.threadtutorial.char02; + +import com.sun.xml.internal.ws.api.pipe.SyncStartForAsyncFeature; + +/** + * Created by byhieg on 17/1/1. + * Mail to byhieg@gmail.com + */ +public class MyObject { + + synchronized public void methodA(){ + try{ + System.out.println("begin methodA threadName=" + Thread.currentThread().getName() + + " begin time =" + System.currentTimeMillis()); + Thread.sleep(5000); + System.out.println("end"); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + synchronized public void methodB(){ + try{ + System.out.println("begin methodB threadName=" + Thread.currentThread().getName() + + " begin time =" + System.currentTimeMillis()); + Thread.sleep(5000); + System.out.println("end"); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/MyOneList.java b/src/main/java/cn/byhieg/threadtutorial/char02/MyOneList.java new file mode 100644 index 0000000..eb537c3 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/MyOneList.java @@ -0,0 +1,20 @@ +package cn.byhieg.threadtutorial.char02; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class MyOneList { + + private List list = new ArrayList(); + synchronized public void add(String data){ + list.add(data); + } + + synchronized public int getSize(){ + return list.size(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/MyOneListService.java b/src/main/java/cn/byhieg/threadtutorial/char02/MyOneListService.java new file mode 100644 index 0000000..18533e6 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/MyOneListService.java @@ -0,0 +1,23 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class MyOneListService { + + + public MyOneList addServiceMethod(MyOneList list,String data){ + try{ + synchronized (list){ + if (list.getSize() < 1){ + Thread.sleep(1000 * 2); + list.add(data); + } + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + return list; + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/ObjectService.java b/src/main/java/cn/byhieg/threadtutorial/char02/ObjectService.java new file mode 100644 index 0000000..1c08932 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/ObjectService.java @@ -0,0 +1,31 @@ +package cn.byhieg.threadtutorial.char02; + +import cn.byhieg.threadtutorial.char01.ExampleSuspendThread; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class ObjectService { + + public void serviceMethodA(){ + try{ + synchronized (this){ + System.out.println("A begin time=" + System.currentTimeMillis()); + Thread.sleep(2000); + System.out.println("A end time =" + System.currentTimeMillis()); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + public void serviceMethodB(){ + synchronized (this){ + System.out.println("B begin time=" + System.currentTimeMillis()); + System.out.println("B end time=" + System.currentTimeMillis()); + } + } + + +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/OutClass.java b/src/main/java/cn/byhieg/threadtutorial/char02/OutClass.java new file mode 100644 index 0000000..fae4b68 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/OutClass.java @@ -0,0 +1,57 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/4. + * Mail byhieg@gmail.com + */ +public class OutClass { + + public static class InnerClass1 { + public void method1(InnerClass2 class2) { + String threadName = Thread.currentThread().getName(); + synchronized (class2) { + System.out.println(threadName + "进入InnerClass1类中的method1方法"); + for (int i = 1; i < 10; i++) { + System.out.println(" i=" + i); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + System.out.println(threadName + "离开InnerClass1类中的method1方法"); + } + } + + synchronized public void method2() { + String threadName = Thread.currentThread().getName(); + System.out.println(threadName + "进入InnerClass1类中的method2方法"); + for (int j = 0; j <= 10; j++) { + System.out.println(" j=" + j); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + + } + } + System.out.println(threadName +" 离开InnerClass1类中的method2方法"); + } + } + + public static class InnerClass2 { + synchronized public void method1() { + String threadName = Thread.currentThread().getName(); + System.out.println(threadName + "进入InnerClass2类中的method1方法"); + for (int k = 1; k < 10; k++) { + System.out.println(" k=" + k); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + System.out.println(threadName + " 离开InnerClass2类中的method1方法"); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/PrintString.java b/src/main/java/cn/byhieg/threadtutorial/char02/PrintString.java new file mode 100644 index 0000000..f4cadbd --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/PrintString.java @@ -0,0 +1,32 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/4. + * Mail byhieg@gmail.com + */ +public class PrintString implements Runnable { + + private boolean isContinuePrint = true; + public boolean isContinuePrint(){ + return isContinuePrint; + } + + public void setContinuePrint(boolean continuePrint) { + isContinuePrint = continuePrint; + } + + public void printStringMethod(){ + try { + while (isContinuePrint == true){ + System.out.println("run printStringMethod threadName=" + Thread.currentThread().getName()); + Thread.sleep(1000); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + public void run() { + printStringMethod(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/PublicVar.java b/src/main/java/cn/byhieg/threadtutorial/char02/PublicVar.java new file mode 100644 index 0000000..d0aa045 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/PublicVar.java @@ -0,0 +1,28 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/1. + * Mail to byhieg@gmail.com + */ +public class PublicVar { + + public String username = "A"; + public String password = "AA"; + + synchronized public void setValue(String username,String password){ + try{ + this.username = username; + Thread.sleep(3000); + this.password = password; + System.out.println("setValue method thread name=" + Thread.currentThread().getName() + " username=" + + username + " password=" + password); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + public void getValue(){ + System.out.println("getValue method thread name=" + Thread.currentThread().getName() + " username=" + username + + " password=" + password); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/PublicVarThreadA.java b/src/main/java/cn/byhieg/threadtutorial/char02/PublicVarThreadA.java new file mode 100644 index 0000000..8bcfb80 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/PublicVarThreadA.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/1. + * Mail to byhieg@gmail.com + */ +public class PublicVarThreadA extends Thread { + + private PublicVar publicVar; + public PublicVarThreadA(PublicVar publicVar){ + this.publicVar = publicVar; + } + + @Override + public void run() { + super.run(); + publicVar.setValue("B","BB"); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/RunService.java b/src/main/java/cn/byhieg/threadtutorial/char02/RunService.java new file mode 100644 index 0000000..5fc3547 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/RunService.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/5. + * Mail to byhieg@gmail.com + */ +public class RunService { + + volatile private boolean isContinueRun = true; + + public void runMethod() { + + while (isContinueRun == true) { + } + + System.out.println("停下来了"); + } + + public void stopMethod() { + isContinueRun = false; + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/RunThread.java b/src/main/java/cn/byhieg/threadtutorial/char02/RunThread.java new file mode 100644 index 0000000..31d0b6d --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/RunThread.java @@ -0,0 +1,26 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/4. + * Mail byhieg@gmail.com + */ +public class RunThread extends Thread{ + volatile private boolean isRunning = true; + + public boolean isRunning(){ + return isRunning; + } + + public void setRunning(boolean isRunning){ + this.isRunning = isRunning; + } + + @Override + public void run() { + System.out.println("进入run了"); + while (isRunning == true){ + + } + System.out.println("线程被停止"); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SelfPrivateThreadA.java b/src/main/java/cn/byhieg/threadtutorial/char02/SelfPrivateThreadA.java new file mode 100644 index 0000000..590666f --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SelfPrivateThreadA.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/1. + * Mail to byhieg@gmail.com + */ +public class SelfPrivateThreadA extends Thread{ + private HasSelfPrivateNum num; + + + public SelfPrivateThreadA(HasSelfPrivateNum num){ + this.num = num; + } + @Override + public void run() { + super.run(); + num.addI("a"); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SelfPrivateThreadB.java b/src/main/java/cn/byhieg/threadtutorial/char02/SelfPrivateThreadB.java new file mode 100644 index 0000000..0c0e610 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SelfPrivateThreadB.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/1. + * Mail to byhieg@gmail.com + */ +public class SelfPrivateThreadB extends Thread{ + private HasSelfPrivateNum num; + + + public SelfPrivateThreadB(HasSelfPrivateNum num){ + this.num = num; + } + @Override + public void run() { + super.run(); + num.addI("b"); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SonSynService.java b/src/main/java/cn/byhieg/threadtutorial/char02/SonSynService.java new file mode 100644 index 0000000..eb41aae --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SonSynService.java @@ -0,0 +1,21 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class SonSynService extends FatherSynService{ + + synchronized public void operateISubMethod(){ + try{ + while (i > 0){ + i--; + System.out.println("sub print i=" + i); + Thread.sleep(1000); + this.operateIMainMethod(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SonSynTread.java b/src/main/java/cn/byhieg/threadtutorial/char02/SonSynTread.java new file mode 100644 index 0000000..0d55ecc --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SonSynTread.java @@ -0,0 +1,14 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class SonSynTread extends Thread{ + @Override + public void run() { + super.run(); + SonSynService son = new SonSynService(); + son.operateISubMethod(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/StaticService.java b/src/main/java/cn/byhieg/threadtutorial/char02/StaticService.java new file mode 100644 index 0000000..69b5d95 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/StaticService.java @@ -0,0 +1,34 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class StaticService { + + synchronized public static void printA(){ + try{ + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 进入printA"); + Thread.sleep(1000 * 3); + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 离开printA"); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + synchronized public static void printB(){ + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 进入printB"); + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 离开printB"); + } + + synchronized public void printC(){ + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 进入printC"); + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 离开printC"); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SynBlockService.java b/src/main/java/cn/byhieg/threadtutorial/char02/SynBlockService.java new file mode 100644 index 0000000..23ac219 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SynBlockService.java @@ -0,0 +1,30 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class SynBlockService { + + private String usernameParam; + private String passwrodParam; + + + public void setUSernamePassword(String username,String password){ + String anyString = new String(); + try{ + synchronized (anyString){ + System.out.println("线程名称为:" + Thread.currentThread().getName() + " 在 " + + System.currentTimeMillis() + " 进入同步块"); + + usernameParam = username; + Thread.sleep(1000 * 3); + passwrodParam = password; + System.out.println("线程名称为:" + Thread.currentThread().getName() + " 在 " + + System.currentTimeMillis() + " 离开同步块"); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SynBlockThreadA.java b/src/main/java/cn/byhieg/threadtutorial/char02/SynBlockThreadA.java new file mode 100644 index 0000000..19b79bd --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SynBlockThreadA.java @@ -0,0 +1,20 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class SynBlockThreadA extends Thread{ + + private SynBlockService service; + + public SynBlockThreadA(SynBlockService service){ + this.service = service; + } + + @Override + public void run() { + super.run(); + service.setUSernamePassword("a","aa"); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SynBlockThreadB.java b/src/main/java/cn/byhieg/threadtutorial/char02/SynBlockThreadB.java new file mode 100644 index 0000000..adbc7cf --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SynBlockThreadB.java @@ -0,0 +1,20 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class SynBlockThreadB extends Thread{ + + private SynBlockService service; + + public SynBlockThreadB(SynBlockService service){ + this.service = service; + } + + @Override + public void run() { + super.run(); + service.setUSernamePassword("b","bb"); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SynVolaThreadA.java b/src/main/java/cn/byhieg/threadtutorial/char02/SynVolaThreadA.java new file mode 100644 index 0000000..9c05626 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SynVolaThreadA.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/5. + * Mail to byhieg@gmail.com + */ +public class SynVolaThreadA extends Thread{ + + private RunService service; + public SynVolaThreadA(RunService service){ + this.service = service; + } + + @Override + public void run() { + super.run(); + service.runMethod(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SynVolaThreadB.java b/src/main/java/cn/byhieg/threadtutorial/char02/SynVolaThreadB.java new file mode 100644 index 0000000..14f7e15 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SynVolaThreadB.java @@ -0,0 +1,20 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/5. + * Mail to byhieg@gmail.com + */ +public class SynVolaThreadB extends Thread{ + + private RunService service; + + public SynVolaThreadB(RunService service){ + this.service = service; + } + + @Override + public void run() { + super.run(); + service.stopMethod(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SynchronizedMethodThread.java b/src/main/java/cn/byhieg/threadtutorial/char02/SynchronizedMethodThread.java new file mode 100644 index 0000000..3cbbe02 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SynchronizedMethodThread.java @@ -0,0 +1,26 @@ +package cn.byhieg.threadtutorial.char02; + +import cn.byhieg.threadtutorial.char01.SynchronizedObject; + +/** + * Created by byhieg on 17/1/1. + * Mail to byhieg@gmail.com + */ +public class SynchronizedMethodThread extends Thread{ + + private MyObject object; + + public SynchronizedMethodThread(MyObject object){ + this.object = object; + } + + @Override + public void run() { + super.run(); + if(Thread.currentThread().getName().equals("A")){ + object.methodA(); + }else{ + object.methodB(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SynchronizedService.java b/src/main/java/cn/byhieg/threadtutorial/char02/SynchronizedService.java new file mode 100644 index 0000000..9dfea6f --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SynchronizedService.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class SynchronizedService { + + synchronized public void service1(){ + System.out.println("service1"); + service2(); + } + + synchronized public void service2(){ + System.out.println("service2"); + service3(); + } + + synchronized public void service3(){ + System.out.println("service3"); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/SynchronizedServiceThread.java b/src/main/java/cn/byhieg/threadtutorial/char02/SynchronizedServiceThread.java new file mode 100644 index 0000000..04cf90b --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/SynchronizedServiceThread.java @@ -0,0 +1,14 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class SynchronizedServiceThread extends Thread{ + @Override + public void run() { + super.run(); + SynchronizedService service = new SynchronizedService(); + service.service1(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char02/VolatileThread.java b/src/main/java/cn/byhieg/threadtutorial/char02/VolatileThread.java new file mode 100644 index 0000000..ddf036b --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char02/VolatileThread.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorial.char02; + +/** + * Created by byhieg on 17/1/5. + * Mail to byhieg@gmail.com + */ +public class VolatileThread extends Thread{ + volatile public static int count; + + synchronized private static void addCount(){ + for (int i = 0 ; i < 100 ; i++){ + count++; + } + System.out.println("count=" + count); + } + + @Override + public void run() { + super.run(); + addCount(); + } +} diff --git "a/src/main/java/cn/byhieg/threadtutorial/char02/\345\244\232\347\272\277\347\250\213\347\254\254\344\272\214\347\253\240\347\237\245\350\257\206\347\202\271\346\200\273\347\273\223.md" "b/src/main/java/cn/byhieg/threadtutorial/char02/\345\244\232\347\272\277\347\250\213\347\254\254\344\272\214\347\253\240\347\237\245\350\257\206\347\202\271\346\200\273\347\273\223.md" new file mode 100644 index 0000000..93e02e4 --- /dev/null +++ "b/src/main/java/cn/byhieg/threadtutorial/char02/\345\244\232\347\272\277\347\250\213\347\254\254\344\272\214\347\253\240\347\237\245\350\257\206\347\202\271\346\200\273\347\273\223.md" @@ -0,0 +1,534 @@ +# Java多线程基础——对象及变量并发访问 +在开发多线程程序时,如果每个多线程处理的事情都不一样,每个线程都互不相关,这样开发的过程就非常轻松。但是很多时候,多线程程序是需要同时访问同一个对象,或者变量的。这样,一个对象同时被多个线程访问,会出现处理的结果和预期不一致的可能。因此,需要了解如何对对象及变量并发访问,写出线程安全的程序,所谓线程安全就是处理的对象及变量的时候是同步处理的,在处理的时候其他线程是不会干扰。本文将从以下几个角度阐述这个问题。所有的代码都在[char02](https://github.com/byhieg/JavaTutorial/tree/master/src/main/java/cn/byhieg/threadtutorial/char02) +1. 对于方法的同步处理 +2. 对于语句块的同步处理 +3. 对类加锁的同步处理 +3. 保证可见性的关键字——volatile + +## 对于方法的同步处理 +对于一个对象的方法,如果有两个线程同时访问,如果不加控制,访问的结果会出乎意料。所以我们需要对方法进行同步处理,让一个线程先访问,等访问结束,在让另一个线程去访问。对于要处理的方法,用`synchronized`修饰该方法。我们下面看一下对比的例子。 +首先是没有同步修饰的方法,看看会有什么意料之外的事情 +``` +public class HasSelfPrivateNum { + private int num = 0; + public void addI(String username){ + try{ + if (username.equals("a")){ + num = 100; + System.out.println("a set over!"); + Thread.sleep(2000); + }else { + num = 200; + System.out.println("b set over!"); + } + System.out.println(username + " num=" + num); + }catch (Exception e){ + e.printStackTrace(); + } + } +} + +public class SelfPrivateThreadA extends Thread{ + private HasSelfPrivateNum num; + public SelfPrivateThreadA(HasSelfPrivateNum num){ + this.num = num; + } + @Override + public void run() { + super.run(); + num.addI("a"); + } +} + +public class SelfPrivateThreadB extends Thread{ + private HasSelfPrivateNum num; + public SelfPrivateThreadB(HasSelfPrivateNum num){ + this.num = num; + } + @Override + public void run() { + super.run(); + num.addI("b"); + } +} +``` +测试的方法如下: +``` +public class HasSelfPrivateNumTest extends TestCase { + public void testAddI() throws Exception { + HasSelfPrivateNum numA = new HasSelfPrivateNum(); +// HasSelfPrivateNum numB = new HasSelfPrivateNum(); + SelfPrivateThreadA threadA = new SelfPrivateThreadA(numA); + threadA.start(); + SelfPrivateThreadB threadB = new SelfPrivateThreadB(numA); + threadB.start(); + + Thread.sleep(1000 * 3); + } + +} +``` +在这个对象中,有一个成员变量num, 如果username是a,则num应该等于100,如果是b,则num应该等于200,threadA与threadB同时去访问addI方法,预期的结果应该是a num=100 b num=200。但是实际的结果如下: +``` +a set over! +b set over! +b num=200 +a num=200 +``` +这是为什么呢?因为threadA先调用addI方法,但是因为传入的参数的是a,所示ThreadA线程休眠2s,这是B线程也已经调用了addI方法,然后将num的值改为了200,这是输出语句输出的是b改之后的num的值也就是200,a的值被b再次修改覆盖了。 +这个方法是线程不安全的,我们给这个方法添加`synchronized`,修改如下: +``` + synchronized public void addI(String username){ + try{ + if (username.equals("a")){ + num = 100; + System.out.println("a set over!"); + Thread.sleep(2000); + }else { + num = 200; + System.out.println("b set over!"); + } + System.out.println(username + " num=" + num); + }catch (Exception e){ + e.printStackTrace(); + } + } +``` +其他地方保持不变,现在我们在看一下,结果: +``` +a set over! +a num=100 +b set over! +b num=200 +``` +这个结果是不是就符合预期的结果,调用的顺序也是一致的。 +用`synchronized`可以保证多线程调用同一个对象的方法的时候,是同步进行的,注意是同一个对象,也就是说`synchronized`的方法是对象锁,锁住的是对象,如果是不同的对象,就没有这个线程不安全的问题。我们在上面的修改的基础上,去掉 +`synchronized`,然后修改测试方法,让两个线程调用不同对象的方法,修改如下: +``` +public class HasSelfPrivateNumTest extends TestCase { + public void testAddI() throws Exception { + HasSelfPrivateNum numA = new HasSelfPrivateNum(); + HasSelfPrivateNum numB = new HasSelfPrivateNum(); + SelfPrivateThreadA threadA = new SelfPrivateThreadA(numA); + threadA.start(); + SelfPrivateThreadB threadB = new SelfPrivateThreadB(numA); + threadB.start(); + Thread.sleep(1000 * 3); + } +} +``` +结果如下: +``` +b set over! +b num=200 +a set over! +a num=100 +``` +因为threadB是不需要休眠的,所以两个线程同时调用的时候,一定是B线程先出结果,这个结果是符合预期的。但是这样是无法证明`synchronized`是对象锁的,只能说明不同线程访问不同对象是不会出现线程不安全的情况的。在补充一个例子来证明:同一个对象,有两个同步方法,但是两个线程分别调用其中一个同步方法,如果返回的结果不是同时出现的,则说明是对象锁,即锁住了一个对象,该对象的其他方法也要等该对象锁释放,才能调用。 +``` +public class MyObject { + + synchronized public void methodA(){ + try{ + System.out.println("begin methodA threadName=" + Thread.currentThread().getName()+ + " begin time =" + System.currentTimeMillis()); + Thread.sleep(5000); + System.out.println("end"); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + synchronized public void methodB(){ + try{ + System.out.println("begin methodB threadName=" + Thread.currentThread().getName() + + " begin time =" + System.currentTimeMillis()); + Thread.sleep(5000); + System.out.println("end"); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} + +public class SynchronizedMethodThread extends Thread{ + + private MyObject object; + + public SynchronizedMethodThread(MyObject object){ + this.object = object; + } + + @Override + public void run() { + super.run(); + if(Thread.currentThread().getName().equals("A")){ + object.methodA(); + }else{ + object.methodB(); + } + } +} +``` +测试方法如下: +``` +public class SynchronizedMethodThreadTest extends TestCase { + public void testRun() throws Exception { + MyObject object = new MyObject(); + SynchronizedMethodThread a = new SynchronizedMethodThread(object); + a.setName("A"); + SynchronizedMethodThread b = new SynchronizedMethodThread(object); + b.setName("B"); + + a.start(); + b.start(); + + Thread.sleep(1000 * 15); + } + +} +``` +A,B两个线程分别调用methodA与methodB, 两个方法也打印出了他们的开始和结束时间。 +结果如下: +``` +begin methodA threadName=A begin time =1483603953885 +end +begin methodB threadName=B begin time =1483603958886 +end +``` +可以看出两个方法是同步调用,一前一后,结果无交叉。说明`synchronized`修饰方法添加的确实是对象锁。 +这样,用`synchronized`修饰的方法,都需要多线程同步调用,但是没用他修饰的方法,多线程还是直接去调用的。也就是说,虽然多线程会同步调用`synchronized`修饰的方法,但是在一个线程同步调用方法的时候,其他线程可能先调用了非同步方法,这个在某些时候会有问题。比如出现脏读。 +A线程先同步调用了set方法,但是可能在set的过程中出现了等待,然后其他线程在get的时候,数据是set还没有执行完的数据。看如下代码: +``` +public class PublicVar { + + public String username = "A"; + public String password = "AA"; + + synchronized public void setValue(String username,String password){ + try{ + this.username = username; + Thread.sleep(3000); + this.password = password; + System.out.println("setValue method thread name=" + Thread.currentThread().getName() + " username=" + + username + " password=" + password); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + public void getValue(){ + System.out.println("getValue method thread name=" + Thread.currentThread().getName() + " username=" + username + + " password=" + password); + } +} + +public class PublicVarThreadA extends Thread { + + private PublicVar publicVar; + public PublicVarThreadA(PublicVar publicVar){ + this.publicVar = publicVar; + } + + @Override + public void run() { + super.run(); + publicVar.setValue("B","BB"); + } +} +``` +看测试的例子: +``` +public class PublicVarThreadATest extends TestCase { + public void testRun() throws Exception { + PublicVar publicVarRef = new PublicVar(); + PublicVarThreadA threadA = new PublicVarThreadA(publicVarRef); + threadA.start(); + Thread.sleep(40); + publicVarRef.getValue(); + Thread.sleep(1000 * 5); + + } + +} +``` +期待的结果应该是"A","AA",或者是"B","BB",然而结果是: +``` +getValue method thread name=main username=B password=AA +setValue method thread name=Thread-0 username=B password=BB +``` +所以,对于同一个对象中的数据读与取,都需要用`synchronized`修饰才能同步。脏读一定会出现在操作对象情况下,多线程"争抢"对象的结果。 +下面,说一些同步方法其他特性,当一个线程得到一个对象锁的时候,他再次请求对象锁,一定会再次得到该对象的锁。这往往出现在一个对象方法里调用这个对象的另一个方法,而这两个方法都是同步的。这样设计是有原因,因为如果不能再次获得这个对象锁的话,很容易造成死锁。这种直接获取锁的方式称之为可重入锁。 +Java中的可重入锁支持在继承中使用,也就是说可以在子类的同步方法中调用父类的同步方法。 +下面,看个例子: +``` +public class FatherSynService { + + public int i = 10; + synchronized public void operateIMainMethod(){ + try{ + i--; + System.out.println("main print i=" +i); + Thread.sleep(100); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} + +public class SonSynService extends FatherSynService{ + + synchronized public void operateISubMethod(){ + try{ + while (i > 0){ + i--; + System.out.println("sub print i=" + i); + Thread.sleep(1000); + this.operateIMainMethod(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} + +public class SonSynTread extends Thread{ + @Override + public void run() { + super.run(); + SonSynService son = new SonSynService(); + son.operateISubMethod(); + } +} +``` +测试的例子如下: +``` +public class SonSynTreadTest extends TestCase { + public void testRun() throws Exception { + SonSynTread thread = new SonSynTread(); + thread.start(); + + Thread.sleep(1000 * 10); + } +} +``` +结果就是i是连续输出的。这说明,当存在父子类继承关系时,子类是完全可以通过"可重入锁"调用父类的同步方法的。但是在继承关系中,同步是不会被继承的,也就是说如果父类的方法是同步的方法,然而子类在覆写该方法的时候,没有加同步的修饰,则子类的方法不算是同步方法。 +关于同步方法还有一点,就是同步方法出现未捕获的异常,则自动释放锁。 + +## 对于语句块的同步处理 +对于上面的同步方法而言,其实是有些弊端的,如果同步方法是需要执行一个很长时间的任务,那么多线程在排队处理同步方法时就会等待很久,但是一个方法中,其实并不是所有的代码都需要同步处理的,只有可能会发生线程不安全的代码才需要同步。这时,可以采用`synchronized`来修饰语句块让关键的代码进行同步。用`synchronized`修饰同步块,其格式如下: +``` +synchronized(对象){ + //语句块 +} +``` +这里的对象,可以是当前类的对象this,也可以是任意的一个Object对象,或者间接继承自Object的对象,只要保证`synchronized`修饰的对象被多线程访问的是同一个,而不是每次调用方法的时候都是新生成就就可以。但是特别注意String对象,因为JVM有String常量池的原因,所以相同内容的字符串实际上就是同一个对象,在用同步语句块的时候尽可能不用String。 +下面,看一个例子来说明同步语句块的用法和与同步方法的区别: + +``` +public class LongTimeTask { + private String getData1; + private String getData2; + + public void doLongTimeTask(){ + try{ + System.out.println("begin task"); + Thread.sleep(3000); + String privateGetData1 = "长时间处理任务后从远程返回的值 1 threadName=" + Thread.currentThread().getName(); + String privateGetData2 = "长时间处理任务后从远程返回的值 2 threadName=" + Thread.currentThread().getName(); + + synchronized (this){ + getData1 = privateGetData1; + getData2 = privateGetData2; + } + + System.out.println(getData1); + System.out.println(getData2); + System.out.println("end task"); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} + +public class LongTimeServiceThreadA extends Thread{ + + private LongTimeTask task; + public LongTimeServiceThreadA(LongTimeTask task){ + super(); + this.task = task; + } + + @Override + public void run() { + super.run(); + CommonUtils.beginTime1 = System.currentTimeMillis(); + task.doLongTimeTask(); + CommonUtils.endTime1 = System.currentTimeMillis(); + } +} + +public class LongTimeServiceThreadB extends Thread{ + + private LongTimeTask task; + public LongTimeServiceThreadB(LongTimeTask task){ + super(); + this.task = task; + } + + @Override + public void run() { + super.run(); + CommonUtils.beginTime2 = System.currentTimeMillis(); + task.doLongTimeTask(); + CommonUtils.endTime2 = System.currentTimeMillis(); + } +} +``` +测试的代码如下: +``` +public class LongTimeServiceThreadATest extends TestCase { + + public void testRun() throws Exception { + LongTimeTask task = new LongTimeTask(); + LongTimeServiceThreadA threadA = new LongTimeServiceThreadA(task); + threadA.start(); + + LongTimeServiceThreadB threadB = new LongTimeServiceThreadB(task); + threadB.start(); + + try{ + Thread.sleep(1000 * 10); + }catch (InterruptedException e){ + e.printStackTrace(); + } + + long beginTime = CommonUtils.beginTime1; + if (CommonUtils.beginTime2 < CommonUtils.beginTime1){ + beginTime = CommonUtils.beginTime2; + } + + long endTime = CommonUtils.endTime1; + if (CommonUtils.endTime2 < CommonUtils.endTime1){ + endTime = CommonUtils.endTime2; + } + System.out.println("耗时:" + ((endTime - beginTime) / 1000)); + + Thread.sleep(1000 * 20); + } + +} +``` +结果如下: +``` +begin task +begin task +长时间处理任务后从远程返回的值 1 threadName=Thread-1 +长时间处理任务后从远程返回的值 2 threadName=Thread-1 +end task +长时间处理任务后从远程返回的值 1 threadName=Thread-1 +长时间处理任务后从远程返回的值 2 threadName=Thread-1 +end task +耗时:3 +``` +两个线程并发处理耗时任务只用了3s, 因为只在赋值的时候进行同步处理,同步语句块以外的部分都是多个线程异步处理的。 +下面,说一下同步语句块的一些特性: +1. 当多个线程同时执行`synchronized(x){}`同步代码块时呈同步效果。 +2. 当其他线程执行x对象中的`synchronized`同步方法时呈同步效果。 +3. 当其他线程执行x对象中的`synchronized(this)`代码块时也呈现同步效果。 + +细说一下每个特性,第一个特性上面的例子已经阐述了,就不多说了。第二个特性,因为同步语句块也是对象锁,所有当对x加锁的时候,x对象内的同步方法也呈现同步效果,当x为this的时候,该对象内的其他同步方法也要等待同步语句块执行完,才能执行。第三个特性和上面x为this是不一样的,第三个特性说的是,x对象中有一个方法,该方法中有一个`synchronized(this)`的语句块的时候,也呈现同步效果。即A线程调用了对x加锁的同步语句块的方法,B线程在调用该x对象的`synchronized(this)`代码块是有先后的同步关系。 + +上面说同步语句块比同步方法在某些方法中执行更有效率,同步语句块还有一个优点,就是如果两个方法都是同步方法,第一个方法无限在执行的时候,第二个方法就永远不会被执行。这时可以对两个方法做同步语句块的处理,设置不同的锁对象,则可以实现两个方法异步执行。 + +## 对类加锁的同步处理 +和对象加锁的同步处理一致,对类加锁的方式也有两种,一种是`synchronized`修饰静态方法,另一种是使用`synchronized(X.class)`同步语句块。在执行上看,和对象锁一致都是同步执行的效果,但是和对象锁却有本质的不同,对对象加锁是访问同一个对象的时候成同步的状态,不同的对象就不会。但是对类加锁是用这个类的静态方法都是呈现同步状态。 +下面,看这个例子: +``` +public class StaticService { + synchronized public static void printA(){ + try{ + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 进入printA"); + Thread.sleep(1000 * 3); + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 离开printA"); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + synchronized public static void printB(){ + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 进入printB"); + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 离开printB"); + } + + synchronized public void printC(){ + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 进入printC"); + System.out.println(" 线程名称为:" + Thread.currentThread().getName() + + " 在 " + System.currentTimeMillis() + " 离开printC"); + } +} +``` +测试方法如下: +``` +public class StaticServiceTest extends TestCase { + + public void testPrint() throws Exception{ + new Thread(new Runnable() { + public void run() { + StaticService.printA(); + } + }).start(); + + new Thread(new Runnable() { + public void run() { + StaticService.printB(); + } + }).start(); + + new Thread(new Runnable() { + public void run() { + new StaticService().printC(); + } + }).start(); + + Thread.sleep(1000 * 3); + } + +} +``` +结果如下: +``` + 线程名称为:Thread-0 在 1483630533783 进入printA + 线程名称为:Thread-2 在 1483630533783 进入printC + 线程名称为:Thread-2 在 1483630533783 离开printC + 线程名称为:Thread-0 在 1483630536786 离开printA + 线程名称为:Thread-1 在 1483630536787 进入printB + 线程名称为:Thread-1 在 1483630536787 离开printB +``` +很明显的看出来,对类加锁和对对象加锁两者方法是异步执行的,而对类加锁的两个方法是呈现同步执行。 +其特性也和同步对象锁一样。 + +关于同步加锁的简单使用的介绍就到这里了。最后还有注意一点,锁对象锁的是该对象的内存地址,其存储的内容改变,并不会让多线程并发的时候认为这是不同的锁。所以改变锁对象的内容,并不会同步失效。 + +## 保证可见性的关键字——volatile +在多线程争抢对象的时候,处理该对象的变量的方式是在主内存中读取该变量的值到线程私有的内存中,然后对该变量做处理,处理后将值在写入到主内存中。上面举的例子,之所以出现结果与预期不一致都是因为线程自己将值复制到自己的私有栈后修改结果而不知道其他线程的修改结果。如果我们不用同步的话,我们就需要一个能保持可见的,知道其他线程修改结果的方法。JDK提供了`volatile`关键字,来保持可见性,关键字volatile的作用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量值。但是该关键字并不能保证原子性,以争抢一个对象中的count变量来看下图的具体说明: +![变量在线程私有栈与主内存的关系](http://images.cnblogs.com/cnblogs_com/aigongsi/201204/201204011757234696.jpg) +> java 垃圾回收整理一文中,描述了jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。 + +volatile在此过程中的具体说明如下: +>read and load 从主存复制变量到当前工作内存 +>use and assign 执行代码,改变共享变量值 +>store and write 用工作内存数据刷新主存相关内容 +>其中use and assign 可以多次出现 +>但是这一些操作并不是原子性,也就是 在read load之后,如果主内存count变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,所以计算出来的结果会和预期不一样对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的例如假如线程1,线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值在线程1堆count进行修改之后,会write到主内存中,主内存中的count变量就会变为6线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6导致两个线程及时用volatile关键字修改之后,还是会存在并发的情况。 + +上述对于volatile的解析均摘自[java中volatile关键字的含义](http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html) + +## 总结 +至此,关于Java同步的知识就告一段落了,上文讲的都是比较粗浅的用法,我放在github的代码中有更多的例子,地址是:[char02](https://github.com/byhieg/JavaTutorial/tree/master/src/main/java/cn/byhieg/threadtutorial/char02) +关于多线程通信的知识就放在了char03的代码中。 diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/Add.java b/src/main/java/cn/byhieg/threadtutorial/char03/Add.java new file mode 100644 index 0000000..a7ac35d --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/Add.java @@ -0,0 +1,21 @@ +package cn.byhieg.threadtutorial.char03; + +import javax.activation.MailcapCommandMap; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class Add { + private Object lock; + public Add(Object lock){ + this.lock = lock; + } + + public void add(){ + synchronized (lock){ + MyList.list.add("anyString"); + lock.notifyAll(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/AddThread.java b/src/main/java/cn/byhieg/threadtutorial/char03/AddThread.java new file mode 100644 index 0000000..894c8ce --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/AddThread.java @@ -0,0 +1,18 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class AddThread extends Thread{ + private Add p; + public AddThread(Add p){ + this.p = p; + } + + @Override + public void run() { + super.run(); + p.add(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/CommonNotify.java b/src/main/java/cn/byhieg/threadtutorial/char03/CommonNotify.java new file mode 100644 index 0000000..4f1e5ee --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/CommonNotify.java @@ -0,0 +1,21 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by byhieg on 17/1/15. + * Mail to byhieg@gmail.com + */ +public class CommonNotify { + + private Object object; + public CommonNotify(Object object){ + this.object = object; + } + + public void doNotify(){ + synchronized (object){ + System.out.println("准备通知"); + object.notifyAll(); + System.out.println("通知结束"); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/CommonWait.java b/src/main/java/cn/byhieg/threadtutorial/char03/CommonWait.java new file mode 100644 index 0000000..7b7ffe3 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/CommonWait.java @@ -0,0 +1,21 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by byhieg on 17/1/15. + * Mail to byhieg@gmail.com + */ +public class CommonWait { + + private Object object; + public CommonWait(Object object){ + this.object = object; + } + + public void doSomething() throws Exception{ + synchronized (object){ + System.out.println("begin wait " + Thread.currentThread().getName()); + object.wait(); + System.out.println("end wait " + Thread.currentThread().getName()); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/JoinThread.java b/src/main/java/cn/byhieg/threadtutorial/char03/JoinThread.java new file mode 100644 index 0000000..b23611f --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/JoinThread.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class JoinThread extends Thread{ + @Override + public void run() { + super.run(); + try{ + int secondValue = (int)(Math.random() * 10000); + System.out.println(secondValue); + Thread.sleep(secondValue); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/JoinThreadA.java b/src/main/java/cn/byhieg/threadtutorial/char03/JoinThreadA.java new file mode 100644 index 0000000..664c4cb --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/JoinThreadA.java @@ -0,0 +1,30 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class JoinThreadA extends Thread { + private JoinThreadB b; + public JoinThreadA(JoinThreadB b){ + this.b = b; + } + + @Override + public void run() { + super.run(); + try{ + synchronized (b){ + b.start(); + b.join(); + for (int i = 0 ; i < Integer.MAX_VALUE;i++){ + String newString = new String(); + Math.random(); + } + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/JoinThreadB.java b/src/main/java/cn/byhieg/threadtutorial/char03/JoinThreadB.java new file mode 100644 index 0000000..e9dcc94 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/JoinThreadB.java @@ -0,0 +1,26 @@ +package cn.byhieg.threadtutorial.char03; + +import com.sun.org.apache.xml.internal.res.XMLErrorResources_tr; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class JoinThreadB extends Thread{ + + @Override + public void run() { + super.run(); + try{ + System.out.println(" b run begin timer=" + System.currentTimeMillis()); + Thread.sleep(1000 * 2); + System.out.println(" b run end timer=" + System.currentTimeMillis()); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + synchronized public void bService(){ + System.out.println(" 打印了bService timer= " + System.currentTimeMillis()); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/JoinThreadC.java b/src/main/java/cn/byhieg/threadtutorial/char03/JoinThreadC.java new file mode 100644 index 0000000..ae85e5d --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/JoinThreadC.java @@ -0,0 +1,17 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class JoinThreadC extends Thread{ + private JoinThreadB joinThreadB; + public JoinThreadC(JoinThreadB joinThreadB){ + this.joinThreadB = joinThreadB; + } + + @Override + public void run() { + joinThreadB.bService(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/MyList.java b/src/main/java/cn/byhieg/threadtutorial/char03/MyList.java new file mode 100644 index 0000000..d3d1c6e --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/MyList.java @@ -0,0 +1,20 @@ +package cn.byhieg.threadtutorial.char03; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by shiqifeng on 2017/1/10. + * Mail byhieg@gmail.com + */ +public class MyList { + public static List list = new ArrayList(); + + public static void add(){ + list.add("anyString"); + } + + public static int size(){ + return list.size(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/NotifyServiceThread.java b/src/main/java/cn/byhieg/threadtutorial/char03/NotifyServiceThread.java new file mode 100644 index 0000000..e5fda17 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/NotifyServiceThread.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by shiqifeng on 2017/1/10. + * Mail byhieg@gmail.com + */ +public class NotifyServiceThread extends Thread{ + private Object lock; + public NotifyServiceThread(Object lock){ + this.lock = lock; + } + + @Override + public void run() { + super.run(); + Service service = new Service(); + service.synNotifyMethod(lock); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/NotifyThread.java b/src/main/java/cn/byhieg/threadtutorial/char03/NotifyThread.java new file mode 100644 index 0000000..a8e377c --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/NotifyThread.java @@ -0,0 +1,33 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by shiqifeng on 2017/1/10. + * Mail byhieg@gmail.com + */ +public class NotifyThread extends Thread{ + private Object lock; + public NotifyThread(Object lock){ + super(); + this.lock = lock; + } + + @Override + public void run() { + super.run(); + synchronized (lock){ + for (int i = 0 ; i < 10;i++){ + MyList.add(); + if (MyList.size() == 5) { + lock.notify(); + System.out.println("已经发出了通知"); + } + System.out.println("添加了 " + (i + 1) + " 个"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/README.md b/src/main/java/cn/byhieg/threadtutorial/char03/README.md new file mode 100644 index 0000000..a277cd2 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/README.md @@ -0,0 +1,300 @@ +# Java多线程基础——线程间通信 +在使用多线程的时候,经常需要多个线程进行协作来完成一件事情。在前面两章分析了Java多线程的基本使用以及利用`synchronized`来实现多个线程同步调用方法或者执行代码块。但上面两章的内容涉及到的例子以及使用的多线程代码都是独自运行,两个程序除了竞争同一个对象以外,没有任何联系。 +这次内容将讲解当多个线程需要协作来完成一件事情的时候,如何去等待其他线程执行,又如何当线程执行完去通知其他线程结束等待。 +本次主要介绍如下内容: +- 等待/通知机制 +- join方法的使用 + +所有的代码均在[char03线程间通信](https://github.com/byhieg/JavaTutorial/tree/master/src/main/java/cn/byhieg/threadtutorial/char03) + +## 等待/通知机制 +Java中对多线程类提供了两个方法来完成等待/通知机制,等待的方法是-`wait()`,通知的方法是`notify()`。先说一下什么是等待/通知机制,所谓等待/通知机制,就是线程A在执行的时候,需要一个其他线程来提供的结果,但是其他线程还没有告诉他这个结果是什么,于是线程A开始等待,当其他线程计算出结果之后就将结果通知给线程A,A线程唤醒,继续执行。这个过程就是等待/通知机制。 +等待/通知机制实际上多个线程之间的一种互动,而为了保证这个互动仅限于期望的那些线程,因此需要多个线程拥有一个统一的对象监视器,也就是都要在`synchronized(x)`同步代码块中执行`x.wait`以及`x.notify`方法。 +如果细心观察,会发现wait方法和notify方法是Object类自带的方法。这个原因是因为任何一个对象都能成为监视器,而wait和notify只有对同一个监视器才能起到预期的作用。也就是说任何一个监视器都能用wait以及notify方法,任何对象都有的方法,自然就需要放到Object中 +### wait方法与notify方法的讲解 +wait方法会使执行该wait方法的线程停止,直到等到了notify的通知。细说一下,执行了wait方法的那个线程会因为wait方法而进入等待状态,该线程也会进入阻塞队列中。而执行了notify那个线程在执行完同步代码之后会通知在阻塞队列中的线程,使其进入就绪状态。被重新唤醒的线程会试图重新获得临界区的控制权,也就是对象锁,然后继续执行临界区也就是同步语句块中wait之后的代码。 +上面这个描述,可以看出一些细节。 +1. wait方法进入了阻塞队列,而上文讲过执行notify操作的线程与执行wait的线程是拥有同一个对象监视器,也就说wait方法执行之后,立刻释放掉锁,这样,另一个线程才能执行同步代码块,才能执行notify。 +2. notify线程会在执行完同步代码之后通知在阻塞队列中的线程,也就是说notify的那个线程并不是立即释放锁,而是在同步方法执行完,释放锁以后,wait方法的那个线程才会继续执行。 +3. 被重新唤醒的线程会试图重新获得锁,也就说,在notify方法的线程释放掉锁以后,其通知的线程是不确定的,看具体是哪一个阻塞队列中的线程获取到对象锁。 + +下面看一个例子: +``` +public class Service { + public void testMethod(Object lock){ + try{ + synchronized (lock){ + System.out.println("begin wait()"); + lock.wait(); + System.out.println(" end wait()"); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + public void synNotifyMethod(Object lock){ + try{ + synchronized (lock){ + System.out.println("begin notify() ThreadName=" + Thread.currentThread().getName() + + " time=" +System.currentTimeMillis()); + lock.notify(); + Thread.sleep(1000 * 1); + System.out.println("end notify() ThreadName=" + Thread.currentThread().getName() + + " time=" + System.currentTimeMillis()); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} +``` +该Service中有两个方法,一个是testMethod方法,包含了wait方法,另一个是synNotifyMethod方法了notify方法,我们首先看一下,wait方法会释放锁的测试。 +``` +public class ServiceThread extends Thread{ + private Object lock; + + public ServiceThread(Object lock){ + this.lock = lock; + } + + @Override + public void run() { + super.run(); + Service service = new Service(); + service.testMethod(lock); + } +} +``` +测试方法如下: +``` +public void testRun() throws Exception { + Object lock = new Object(); + new ServiceThread(lock).start(); + new ServiceThread(lock).start(); + Thread.sleep(1000 * 4); +} +``` +结果如下: +``` +begin wait() +begin wait() +``` +很明显结果是执行了2次同步代码块,其执行的原因,就是因为第一个wait之后,释放掉了对象锁,所以第二个线程才会执行同步代码块。 + +还是利用上面的代码,现在我们看一下,notify方法通知等待的线程, 但是不会立即释放锁的例子。 +``` +public class NotifyServiceThread extends Thread{ + private Object lock; + public NotifyServiceThread(Object lock){ + this.lock = lock; + } + + @Override + public void run() { + super.run(); + Service service = new Service(); + service.synNotifyMethod(lock); + } +} +``` +测试的例子如下: +``` +public class NotifyServiceThreadTest extends TestCase { + public void testRun() throws Exception { + Object lock = new Object(); + ServiceThread a = new ServiceThread(lock); + a.start(); + Thread.sleep(1000); + new NotifyServiceThread(lock).start(); + new NotifyServiceThread(lock).start(); + + Thread.sleep(1000 * 10); + } + +} +``` +其结果如下: +``` +begin wait() +begin notify() ThreadName=Thread-1 time=1484302436105 +end notify() ThreadName=Thread-1 time=1484302437108 +end wait() +begin notify() ThreadName=Thread-2 time=1484302437108 +end notify() ThreadName=Thread-2 time=1484302438110 +``` +测试方法,首先调用上wait的例子,让ServiceThread线程进入等待状态,然后执行2个含有notify操作的线程,可以看出,第一个notify执行完,wait线程并没有立即开始运行,而是Thread-1继续执行后续的notify方法,直到同步语句块结束,然后wait线程立即得到锁,并继续运行。之后Thread-2开始运行,直到结束,因为已经没有等待的线程,所以不会有后续的等待的线程运行。 +这里,可以看出一个细节,竞争锁的线程有3个,一个包含wait线程,两个包含notify线程。第一个notify执行结束,获得锁一定是阻塞的线程,而不是另一个notify的线程。 +上面的程序展现了等待/通知机制是如何通过wait和notify实现。在这里,我们可以看出wait方法使线程进入等待,和`Thread.sleep`是很相似的。但是两者却截然不同,区别如下: +- wait使线程进入等待,是可以被通知唤醒的,但是sleep只能自己到时间唤醒。 +- wait方法是对象锁调用的成员方法,而sleep却是Thread类的静态方法 +- wait方法出现在同步方法或者同步代码块中,但是sleep方法可以出现在非同步代码中。 + +wait和notify还提供了几个其他API,如`wait(long timeout)`该方法可以提供一个唤醒的时间,如果在时间内,没有其他线程唤醒该等待线程,则到设定的时间,会自动结束等待。 +因为notify仅仅能唤醒一个线程,所以Java提供了一个`notifyAll()`的方法来唤醒所有的线程,让所有的线程来竞争。我们看一下只唤醒一个线程和唤醒所有线程的不同。 +``` +public class CommonWait { + + private Object object; + public CommonWait(Object object){ + this.object = object; + } + + public void doSomething() throws Exception{ + synchronized (object){ + System.out.println("begin wait " + Thread.currentThread().getName()); + object.wait(); + System.out.println("end wait " + Thread.currentThread().getName()); + } + } +} +``` +``` +public class CommonNotify { + + private Object object; + public CommonNotify(Object object){ + this.object = object; + } + + public void doNotify(){ + synchronized (object){ + System.out.println("准备通知"); + object.notify(); + System.out.println("通知结束"); + } + } +} +``` +测试通知一个等待线程 +``` + public void testRun() throws Exception{ + Object lock = new Object(); + new Thread(()->{ + try { + new CommonWait(lock).doSomething(); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + + new Thread(()->{ + try { + new CommonWait(lock).doSomething(); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + + Thread.sleep(1000); + + new Thread(()->{ + new CommonNotify(lock).doNotify(); + }).start(); + + Thread.sleep(1000 * 3); + + } +``` +结果如下: +``` +begin wait Thread-0 +begin wait Thread-1 +准备通知 +通知结束 +end wait Thread-0 +``` +结果看来,只有一个线程结束了等待,继续往下面执行。另一个线程直到结束也没有执行。 +现在看一下notifyAll的效果,把`CommonNotify`这个类中的`object.notify();`改成`object.notifyAll()` +其他的不变,看看结果: +``` +begin wait Thread-0 +begin wait Thread-1 +准备通知 +通知结束 +end wait Thread-1 +end wait Thread-0 +``` +很明显,两个等待线程都执行了,而且这次Thread-1的线程先执行,可见通知唤醒是随机的。 +这里详细说一下,这个结果。wait使线程进入了阻塞状态,阻塞状态可以细分为3种: +- 等待阻塞:运行的线程执行wait方法,JVM会把该线程放入等待队列中。 +- 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池当中。 +- 其他阻塞: 运行的线程执行了`Thread.sleep`或者`join`方法,或者发出I/O请求时,JVM会把该线程置为阻塞状态。当`sleep()`状态超时、join()等待线程终止,或者超时、或者I/O处理完毕时,线程重新转入可运行状态。 + +可运行状态就是线程执行`start`时,就是可运行状态,一旦CPU切换到这个线程就开始执行里面的run方法就进入了运行状态。 +上面会出现这个结果,就是因为notify仅仅让一个线程进入了可运行状态,而另一个线程则还在阻塞中。而`notifyAll`则使所有的线程都从等待队列中出来,而因为同步代码的关系,获得锁的线程进入可运行态,没有得到锁的则进入锁池,也是阻塞状态,但是会因为锁的释放而重新进入可运行态。所以notifyAll会让所有wait的线程都会继续执行。 + +## join方法的使用 +wait方法使线程进入阻塞,并且因为通知而唤醒执行,sleep方法同样使线程进入阻塞,并且因此超时而结束阻塞。以上两者都是因为特定的条件而结束阻塞,现在主线程需要知道子线程的结果再继续执行,这个时候要怎么做,用通知/等待不是很容易实现这个操作,sleep则完全不知道要等待的时间。因此Java提供了一个`join()`方法,`join()`方法是Thread对象的方法,他的功能是使所属的线程对象x正常执行run方法的内容,而使当前线程z进行无限期的阻塞,等待线程x销毁后在继续执行线程z后面的代码。这说起来有点绕口,其实看例子就很简单。 +``` +public class JoinThread extends Thread{ + @Override + public void run() { + super.run(); + try{ + int secondValue = (int)(Math.random() * 10000); + System.out.println(secondValue); + Thread.sleep(secondValue); + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} +``` +其测试的方法如下: +``` + public void testRun() throws Exception { + JoinThread joinThread = new JoinThread(); + joinThread.start(); + joinThread.join(); + System.out.println("我想当Join对象执行完毕后我再执行,我做到了"); + + } +``` +结果如下: +``` +3519 +我想当Join对象执行完毕后我再执行,我做到了 +``` +看上去join方法很神奇,可以实现线程在执行上面的次序。但是实际上join方法内部是通过wait实现的。 +``` + public final synchronized void join(long millis) + throws InterruptedException { + long base = System.currentTimeMillis(); + long now = 0; + + if (millis < 0) { + throw new IllegalArgumentException("timeout value is negative"); + } + + if (millis == 0) { + while (isAlive()) { + wait(0); + } + } else { + while (isAlive()) { + long delay = millis - now; + if (delay <= 0) { + break; + } + wait(delay); + now = System.currentTimeMillis() - base; + } + } + } +``` +这个join的原理很简单,前面那些if条件不管,主要看while循环里面的,while循环就是不断去判断`this.isAlive`的结果,用上面的例子,这个this就是`joinThread`。然后关键的代码就是`wait(delay);`一个定时的wait。这个wait的对象也是this,就是`joinThread`。上面我们已经讲了wait一定要在同步方法或者同步代码块中,源码中join方法的修饰符就是一个`synchronized`,表明这是一个同步的方法。 +不要看调用wait是`joinThread`,是一个线程。但是真正因为wait进入阻塞状态的,是持有对象监视器的线程,这里的对象监视器是`joinThread`,持有他的是main线程,因为在main线程中执行了join这个同步方法。 +所以main线程不断的wait,直到调用join方法那个线程对象销毁,才继续向下执行。 +但是源码中只有wait的方法,没有notify的方法。因为notify这个操作是JVM通过检测线程对象销毁而调用的native方法,是C++实现的,在源码中是找不到对应这个wait方法而存在的notify方法的。 + +## 总结 +这里介绍了线程间通信的一种常见的方式——等待/通知机制。此外,还介绍了一种指定线程执行顺序的方法——join方法,并且讲解了其内部的实现。 +全部的代码都在[char03线程间通信](https://github.com/byhieg/JavaTutorial/tree/master/src/main/java/cn/byhieg/threadtutorial/char03) + + + + + + + diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/Service.java b/src/main/java/cn/byhieg/threadtutorial/char03/Service.java new file mode 100644 index 0000000..39799a6 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/Service.java @@ -0,0 +1,35 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by shiqifeng on 2017/1/10. + * Mail byhieg@gmail.com + */ +//对应3.1.4 +public class Service { + public void testMethod(Object lock){ + try{ + synchronized (lock){ + System.out.println("begin wait()"); + lock.wait(); + System.out.println(" end wait()"); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + public void synNotifyMethod(Object lock){ + try{ + synchronized (lock){ + System.out.println("begin notify() ThreadName=" + Thread.currentThread().getName() + + " time=" +System.currentTimeMillis()); + lock.notify(); + Thread.sleep(1000 * 1); + System.out.println("end notify() ThreadName=" + Thread.currentThread().getName() + + " time=" + System.currentTimeMillis()); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/ServiceThread.java b/src/main/java/cn/byhieg/threadtutorial/char03/ServiceThread.java new file mode 100644 index 0000000..4292485 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/ServiceThread.java @@ -0,0 +1,20 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by shiqifeng on 2017/1/10. + * Mail byhieg@gmail.com + */ +public class ServiceThread extends Thread{ + private Object lock; + + public ServiceThread(Object lock){ + this.lock = lock; + } + + @Override + public void run() { + super.run(); + Service service = new Service(); + service.testMethod(lock); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/Subtract.java b/src/main/java/cn/byhieg/threadtutorial/char03/Subtract.java new file mode 100644 index 0000000..02cdf17 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/Subtract.java @@ -0,0 +1,28 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class Subtract { + private Object lock; + public Subtract(Object lock){ + this.lock = lock; + } + + public void subtract(){ + try{ + synchronized (lock){ + while (MyList.list.size() == 0){ + System.out.println("wait begin ThreadName=" + Thread.currentThread().getName()); + lock.wait(); + System.out.println("wait end ThreadName=" + Thread.currentThread().getName()); + } + MyList.list.remove(0); + System.out.println("list size=" + MyList.list.size()); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/SubtractThread.java b/src/main/java/cn/byhieg/threadtutorial/char03/SubtractThread.java new file mode 100644 index 0000000..8c8c9e7 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/SubtractThread.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class SubtractThread extends Thread{ + private Subtract r; + + public SubtractThread(Subtract r){ + this.r = r; + } + + @Override + public void run() { + super.run(); + r.subtract(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/SynService.java b/src/main/java/cn/byhieg/threadtutorial/char03/SynService.java new file mode 100644 index 0000000..a879a42 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/SynService.java @@ -0,0 +1,25 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class SynService { + + public Object o; + public SynService(Object o){ + this.o = o; + } + public void doSomething(){ + synchronized (o){ + System.out.println("开始 " + System.currentTimeMillis()); + System.out.println(Thread.currentThread().getName() + " 执行中"); + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("结束" + System.currentTimeMillis()); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/WaitHasParamThread.java b/src/main/java/cn/byhieg/threadtutorial/char03/WaitHasParamThread.java new file mode 100644 index 0000000..ef80691 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/WaitHasParamThread.java @@ -0,0 +1,38 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by shiqifeng on 2017/1/10. + * Mail byhieg@gmail.com + */ +public class WaitHasParamThread { + + static private Object lock = new Object(); + static private Runnable runnable1 = new Runnable() { + @Override + public void run() { + try{ + synchronized (lock){ + System.out.println("wait begin timer=" + System.currentTimeMillis()); + lock.wait(1000 * 5); + System.out.println("wait end timer=" + System.currentTimeMillis()); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + }; + + static private Runnable runnable2 = () -> { + synchronized (lock){ + System.out.println("notify begin timer=" + System.currentTimeMillis()); + lock.notify(); + System.out.println("notify end timer=" + System.currentTimeMillis()); + } + }; + + public static void main(String[] args) throws InterruptedException { + new Thread(runnable1).start(); + Thread.sleep(1000); + new Thread(runnable2).start(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char03/WaitThread.java b/src/main/java/cn/byhieg/threadtutorial/char03/WaitThread.java new file mode 100644 index 0000000..54ad0bc --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char03/WaitThread.java @@ -0,0 +1,30 @@ +package cn.byhieg.threadtutorial.char03; + +/** + * Created by shiqifeng on 2017/1/10. + * Mail byhieg@gmail.com + */ +public class WaitThread extends Thread{ + private Object lock; + public WaitThread(Object lock){ + super(); + this.lock = lock; + } + + @Override + public void run() { + super.run(); + try{ + synchronized (lock){ + if (MyList.size() != 5){ + System.out.println("开始 wait time =" + System.currentTimeMillis()); + lock.wait(); + System.out.println("结束 wait time = " + System.currentTimeMillis()); + } + + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/ConditionAllService.java b/src/main/java/cn/byhieg/threadtutorial/char04/ConditionAllService.java new file mode 100644 index 0000000..b563dda --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/ConditionAllService.java @@ -0,0 +1,69 @@ +package cn.byhieg.threadtutorial.char04; + +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Created by byhieg on 17/1/27. + * Mail to byhieg@gmail.com + */ + +public class ConditionAllService { + private Lock lock = new ReentrantLock(); + public Condition conditionA = lock.newCondition(); + public Condition conditionB = lock.newCondition(); + + public void awaitA() { + try { + lock.lock(); + System.out.println("begin awaitA时间为 " + System.currentTimeMillis() + + "ThreadName=" + Thread.currentThread().getName()); + conditionA.await(); + System.out.println("end awaitA时间为" + System.currentTimeMillis() + + "ThreadName=" + Thread.currentThread().getName()); + } catch (Exception e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + + public void awaitB() { + try { + lock.lock(); + System.out.println("begin awaitB时间为 " + System.currentTimeMillis() + + "ThreadName=" + Thread.currentThread().getName()); + conditionB.await(); + System.out.println("end awaitB时间为" + System.currentTimeMillis() + + "ThreadName=" + Thread.currentThread().getName()); + } catch (Exception e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + + public void signAAll() { + try { + lock.lock(); + System.out.println("signAll的时间为" + System.currentTimeMillis() + + "ThreadName=" + Thread.currentThread().getName()); + conditionA.signalAll(); + } finally { + lock.unlock(); + } + } + + public void signBAll() { + try { + lock.lock(); + System.out.println("signAll的时间为" + System.currentTimeMillis() + + "ThreadName=" + Thread.currentThread().getName()); + conditionB.signalAll(); + } finally { + lock.unlock(); + } + } + +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/ConditionWaitNotifyService.java b/src/main/java/cn/byhieg/threadtutorial/char04/ConditionWaitNotifyService.java new file mode 100644 index 0000000..ffd73dc --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/ConditionWaitNotifyService.java @@ -0,0 +1,41 @@ +package cn.byhieg.threadtutorial.char04; + +import java.awt.*; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Created by byhieg on 17/1/27. + * Mail to byhieg@gmail.com + */ +public class ConditionWaitNotifyService { + + private Lock lock = new ReentrantLock(); + public Condition condition = lock.newCondition(); + + + public void await(){ + try{ + lock.lock(); + System.out.println("await的时间为 " + System.currentTimeMillis()); + condition.awaitUninterruptibly(); + System.out.println("await结束的时间" + System.currentTimeMillis()); + }catch (Exception e){ + e.printStackTrace(); + }finally { + lock.unlock(); + } + } + + + public void signal(){ + try{ + lock.lock(); + System.out.println("sign的时间为" + System.currentTimeMillis()); + condition.signal(); + }finally { + lock.unlock(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/FairService.java b/src/main/java/cn/byhieg/threadtutorial/char04/FairService.java new file mode 100644 index 0000000..a470daf --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/FairService.java @@ -0,0 +1,31 @@ +package cn.byhieg.threadtutorial.char04; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Created by byhieg on 17/1/27. + * Mail to byhieg@gmail.com + */ +public class FairService { + private Lock lock; + private boolean isFair; + + + public FairService(boolean isFair){ + lock = new ReentrantLock(isFair); + } + + public void setFair(boolean fair) { + isFair = fair; + } + + public void serviceMethod(){ + try{ + lock.lock(); + System.out.println("ThreadName=" + Thread.currentThread().getName() + "获得锁定"); + }finally { + lock.unlock(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/HoldCountService.java b/src/main/java/cn/byhieg/threadtutorial/char04/HoldCountService.java new file mode 100644 index 0000000..6554ea8 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/HoldCountService.java @@ -0,0 +1,33 @@ +package cn.byhieg.threadtutorial.char04; + +import java.util.concurrent.locks.ReentrantLock; + +/** + * Created by byhieg on 17/1/27. + * Mail to byhieg@gmail.com + */ +public class HoldCountService { + private ReentrantLock lock = new ReentrantLock(); + + public void serviceMethod1(){ + try { + lock.lock(); + System.out.println("ServiceMethod1 getHoldCount=" + lock.getHoldCount()); + serviceMethod2(); + }finally { + lock.unlock(); + } + } + + public void serviceMethod2(){ + try { + lock.lock(); + System.out.println("ServiceMethod2 getHoldCount=" + lock.getHoldCount()); + }finally { + lock.unlock(); + } + } + + + +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/MyConditionMoreService.java b/src/main/java/cn/byhieg/threadtutorial/char04/MyConditionMoreService.java new file mode 100644 index 0000000..65d1642 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/MyConditionMoreService.java @@ -0,0 +1,48 @@ +package cn.byhieg.threadtutorial.char04; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Created by byhieg on 17/1/26. + * Mail to byhieg@gmail.com + */ +public class MyConditionMoreService { + + private Lock lock = new ReentrantLock(); + + + public void methodA(){ + try{ + lock.lock(); + System.out.println("methodA begin ThreadName=" + Thread.currentThread().getName() + + " time=" + System.currentTimeMillis()); + Thread.sleep(1000 * 5); + + System.out.println("methodA end ThreadName=" + Thread.currentThread().getName() + + " time=" + System.currentTimeMillis()); + }catch (Exception e){ + e.printStackTrace(); + }finally { + lock.unlock(); + } + } + + public void methodB(){ + try{ + lock.lock(); + System.out.println("methodB begin ThreadName=" + Thread.currentThread().getName() + + " time=" + System.currentTimeMillis()); + Thread.sleep(1000 * 5); + + System.out.println("methodB end ThreadName=" + Thread.currentThread().getName() + + " time=" + System.currentTimeMillis()); + }catch (Exception e){ + e.printStackTrace(); + }finally { + lock.unlock(); + } + } + + +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/MyConditionService.java b/src/main/java/cn/byhieg/threadtutorial/char04/MyConditionService.java new file mode 100644 index 0000000..a241540 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/MyConditionService.java @@ -0,0 +1,21 @@ +package cn.byhieg.threadtutorial.char04; + +import java.awt.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Created by byhieg on 17/1/26. + * Mail to byhieg@gmail.com + */ +public class MyConditionService { + + private Lock lock = new ReentrantLock(); + public void testMethod(){ + lock.lock(); + for (int i = 0 ;i < 5;i++){ + System.out.println("ThreadName = " + Thread.currentThread().getName() + (" " + (i + 1))); + } + lock.unlock(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/ReadMe.md b/src/main/java/cn/byhieg/threadtutorial/char04/ReadMe.md new file mode 100644 index 0000000..dc7e39e --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/ReadMe.md @@ -0,0 +1,451 @@ +之前已经说道,JVM提供了synchronized关键字来实现对变量的同步访问以及用wait和notify来实现线程间通信。在jdk1.5以后,JAVA提供了Lock类来实现和synchronized一样的功能,并且还提供了Condition来显示线程间通信。 +Lock类是Java类来提供的功能,丰富的api使得Lock类的同步功能比synchronized的同步更强大。本文章的所有代码均在[Lock类例子的代码](https://github.com/byhieg/JavaTutorial/tree/master/src/main/java/cn/byhieg/threadtutorial/char04) +本文主要介绍一下内容: + +1. Lock类 +2. Lock类其他功能 +3. Condition类 +4. Condition类其他功能 +5. 读写锁 + +## Lock类 +Lock类实际上是一个接口,我们在实例化的时候实际上是实例化实现了该接口的类`Lock lock = new ReentrantLock();`。用synchronized的时候,synchronized可以修饰方法,或者对一段代码块进行同步处理。 +前面讲过,针对需要同步处理的代码设置对象监视器,比整个方法用synchronized修饰要好。Lock类的用法也是这样,通过Lock对象lock,用`lock.lock`来加锁,用`lock.unlock`来释放锁。在两者中间放置需要同步处理的代码。 +具体的例子如下: + +``` +public class MyConditionService { + + private Lock lock = new ReentrantLock(); + public void testMethod(){ + lock.lock(); + for (int i = 0 ;i < 5;i++){ + System.out.println("ThreadName = " + Thread.currentThread().getName() + (" " + (i + 1))); + } + lock.unlock(); + } +} +``` + +测试的代码如下: + +``` + MyConditionService service = new MyConditionService(); + new Thread(service::testMethod).start(); + new Thread(service::testMethod).start(); + new Thread(service::testMethod).start(); + new Thread(service::testMethod).start(); + new Thread(service::testMethod).start(); + + Thread.sleep(1000 * 5); +``` + +结果太长就不放出来,具体可以看我源码。总之,就是每个线程的打印1-5都是同步进行,顺序没有乱。 +通过下面的例子,可以看出Lock对象加锁的时候也是一个对象锁,持续对象监视器的线程才能执行同步代码,其他线程只能等待该线程释放对象监视器。 + +``` +public class MyConditionMoreService { + + private Lock lock = new ReentrantLock(); + public void methodA(){ + try{ + lock.lock(); + System.out.println("methodA begin ThreadName=" + Thread.currentThread().getName() + + " time=" + System.currentTimeMillis()); + Thread.sleep(1000 * 5); + + System.out.println("methodA end ThreadName=" + Thread.currentThread().getName() + + " time=" + System.currentTimeMillis()); + }catch (Exception e){ + e.printStackTrace(); + }finally { + lock.unlock(); + } + } + + public void methodB(){ + try{ + lock.lock(); + System.out.println("methodB begin ThreadName=" + Thread.currentThread().getName() + + " time=" + System.currentTimeMillis()); + Thread.sleep(1000 * 5); + + System.out.println("methodB end ThreadName=" + Thread.currentThread().getName() + + " time=" + System.currentTimeMillis()); + }catch (Exception e){ + e.printStackTrace(); + }finally { + lock.unlock(); + } + } +} + +``` + +测试代码如下: + +``` + public void testMethod() throws Exception { + MyConditionMoreService service = new MyConditionMoreService(); + ThreadA a = new ThreadA(service); + a.setName("A"); + a.start(); + + ThreadA aa = new ThreadA(service); + aa.setName("AA"); + aa.start(); + + ThreadB b = new ThreadB(service); + b.setName("B"); + b.start(); + + ThreadB bb = new ThreadB(service); + bb.setName("BB"); + bb.start(); + + Thread.sleep(1000 * 30); + } + +public class ThreadA extends Thread{ + + private MyConditionMoreService service; + + public ThreadA(MyConditionMoreService service){ + this.service = service; + } + + @Override + public void run() { + service.methodA(); + } +} + +public class ThreadB extends Thread{ + + private MyConditionMoreService service; + + public ThreadB(MyConditionMoreService service){ + this.service = service; + } + + @Override + public void run() { + super.run(); + service.methodB(); + } +} +``` + +结果如下: + +``` +methodA begin ThreadName=A time=1485590913520 +methodA end ThreadName=A time=1485590918522 +methodA begin ThreadName=AA time=1485590918522 +methodA end ThreadName=AA time=1485590923525 +methodB begin ThreadName=B time=1485590923525 +methodB end ThreadName=B time=1485590928528 +methodB begin ThreadName=BB time=1485590928529 +methodB end ThreadName=BB time=1485590933533 +``` + +可以看出Lock类加锁确实是对象锁。针对同一个lock对象执行的`lock.lock`是获得对象监视器的线程才能执行同步代码 其他线程都要等待。 +在这个例子中,加锁,和释放锁都是在try-finally。这样的好处是在任何异常发生的情况下,都能保障锁的释放。 + +## Lock类其他的功能 +如果Lock类只有lock和unlock方法也太简单了,Lock类提供了丰富的加锁的方法和对加锁的情况判断。主要有 + +- 实现锁的公平 +- 获取当前线程调用lock的次数,也就是获取当前线程锁定的个数 +- 获取等待锁的线程数 +- 查询指定的线程是否等待获取此锁定 +- 查询是否有线程等待获取此锁定 +- 查询当前线程是否持有锁定 +- 判断一个锁是不是被线程持有 +- 加锁时如果中断则不加锁,进入异常处理 +- 尝试加锁,如果该锁未被其他线程持有的情况下成功 + +#### 实现公平锁 +在实例化锁对象的时候,构造方法有2个,一个是无参构造方法,一个是传入一个boolean变量的构造方法。当传入值为true的时候,该锁为公平锁。默认不传参数是非公平锁。 +> 公平锁:按照线程加锁的顺序来获取锁 +> 非公平锁:随机竞争来得到锁 +此外,JAVA还提供`isFair()`来判断一个锁是不是公平锁。 + +#### 获取当前线程锁定的个数 +Java提供了`getHoldCount()`方法来获取当前线程的锁定个数。所谓锁定个数就是当前线程调用lock方法的次数。一般一个方法只会调用一个lock方法,但是有可能在同步代码中还有调用了别的方法,那个方法内部有同步代码。这样,`getHoldCount()`返回值就是大于1。 + +**下面的方法用来判断等待锁的情况** + +#### 获取等待锁的线程数 +Java提供了`getQueueLength()`方法来得到等待锁释放的线程的个数。 +#### 查询指定的线程是否等待获取此锁定 +Java提供了`hasQueuedThread(Thread thread)`查询该Thread是否等待该lock对象的释放。 +#### 查询是否有线程等待获取此锁定 +同样,Java提供了一个简单判断是否有线程在等待锁释放即`hasQueuedThreads()`。 + +**下面的方法用来判断持有锁的情况** + +#### 查询当前线程是否持有锁定 +Java不仅提供了判断是否有线程在等待锁释放的方法,还提供了是否当前线程持有锁即`isHeldByCurrentThread()`,判断当前线程是否有此锁定。 +#### 判断一个锁是不是被线程持有 +同样,Java提供了简单判断一个锁是不是被一个线程持有,即`isLocked()` + +**下面的方法用来实现多种方式加锁** + +#### 加锁时如果中断则不加锁,进入异常处理 +Lock类提供了多种选择的加锁方法,`lockInterruptibly()`也可以实现加锁,但是当线程被中断的时候,就会加锁失败,进行异常处理阶段。一般这种情况出现在该线程已经被打上interrupted的标记了。 + +#### 尝试加锁,如果该锁未被其他线程持有的情况下成功 +Java提供了`tryLock()`方法来进行尝试加锁,只有该锁未被其他线程持有的基础上,才会成功加锁。 + +上面介绍了Lock类来实现代码的同步处理,下面介绍Condition类来实现wait/notify机制。 + +## Condition类 +Condition是Java提供了来实现等待/通知的类,Condition类还提供比wait/notify更丰富的功能,Condition对象是由lock对象所创建的。但是同一个锁可以创建多个Condition的对象,即创建多个对象监视器。这样的好处就是可以指定唤醒线程。notify唤醒的线程是随机唤醒一个。 +下面,看一个例子,显示简单的等待/通知 + +``` +public class ConditionWaitNotifyService { + + private Lock lock = new ReentrantLock(); + public Condition condition = lock.newCondition(); + + + public void await(){ + try{ + lock.lock(); + System.out.println("await的时间为 " + System.currentTimeMillis()); + condition.await(); + System.out.println("await结束的时间" + System.currentTimeMillis()); + }catch (Exception e){ + e.printStackTrace(); + }finally { + lock.unlock(); + } + } + + + public void signal(){ + try{ + lock.lock(); + System.out.println("sign的时间为" + System.currentTimeMillis()); + condition.signal(); + }finally { + lock.unlock(); + } + } +} +``` + +测试的代码如下: + +``` + ConditionWaitNotifyService service = new ConditionWaitNotifyService(); + new Thread(service::await).start(); + Thread.sleep(1000 * 3); + service.signal(); + Thread.sleep(1000); +``` + +结果如下: + +``` +await的时间为 1485610107421 +sign的时间为1485610110423 +await结束的时间1485610110423 +``` + +condition对象通过`lock.newCondition()`来创建,用`condition.await()`来实现让线程等待,是线程进入阻塞。用`condition.signal()`来实现唤醒线程。唤醒的线程是用同一个conditon对象调用`await()`方法而进入阻塞。并且和wait/notify一样,await()和signal()也是在同步代码区内执行。 +此外看出await结束的语句是在获取通知之后才执行,确实实现了wait/notify的功能。下面这个例子是展示唤醒制定的线程。 + +``` + ConditionAllService service = new ConditionAllService(); + Thread a = new Thread(service::awaitA); + a.setName("A"); + a.start(); + + Thread b = new Thread(service::awaitB); + b.setName("B"); + b.start(); + + Thread.sleep(1000 * 3); + + service.signAAll(); + + Thread.sleep(1000 * 4); +``` + +结果如下: + +``` +begin awaitA时间为 1485611065974ThreadName=A +begin awaitB时间为 1485611065975ThreadName=B +signAll的时间为1485611068979ThreadName=main +end awaitA时间为1485611068979ThreadName=A +``` + +该结果确实展示用同一个condition对象来实现等待通知。 +对于等待/通知机制,简化而言,就是等待一个条件,当条件不满足时,就进入等待,等条件满足时,就通知等待的线程开始执行。为了实现这种功能,需要进行wait的代码部分与需要进行通知的代码部分必须放在同一个对象监视器里面。执行才能实现多个阻塞的线程同步执行代码,等待与通知的线程也是同步进行。对于wait/notify而言,对象监视器与等待条件结合在一起 即`synchronized(对象)`利用该对象去调用wait以及notify。但是对于Condition类,是对象监视器与条件分开,Lock类来实现对象监视器,condition对象来负责条件,去调用await以及signal。 + +## Condition类的其他功能 +和wait类提供了一个最长等待时间,`awaitUntil(Date deadline)`在到达指定时间之后,线程会自动唤醒。但是无论是await或者awaitUntil,当线程中断时,进行阻塞的线程会产生中断异常。Java提供了一个`awaitUninterruptibly`的方法,使即使线程中断时,进行阻塞的线程也不会产生中断异常。 + +## 读写锁 +Lock类除了提供了`ReentrantLock`的锁以外,还提供了`ReentrantReadWriteLock`的锁。读写锁分成两个锁,一个锁是读锁,一个锁是写锁。读锁与读锁之间是共享的,读锁与写锁之间是互斥的,写锁与写锁之间也是互斥的。 +看下面的读读共享的例子: + +``` +public class ReadReadService { + private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + public void read(){ + try{ + try{ + lock.readLock().lock(); + System.out.println("获得读锁" + Thread.currentThread().getName() + + " " + System.currentTimeMillis()); + Thread.sleep(1000 * 10); + }finally { + lock.readLock().unlock(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} +``` + +测试的代码和结果如下: + +``` + ReadReadService service = new ReadReadService(); + Thread a = new Thread(service::read); + a.setName("A"); + + Thread b = new Thread(service::read); + b.setName("B"); + + a.start(); + b.start(); +``` + +结果如下: + +``` +获得读锁A 1485614976979 +获得读锁B 1485614976981 +``` + +两个线程几乎同时执行同步代码。 +下面的例子是写写互斥的例子 + +``` +public class WriteWriteService { + private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + public void write(){ + try{ + try{ + lock.writeLock().lock(); + System.out.println("获得写锁" + Thread.currentThread().getName() + + " " +System.currentTimeMillis()); + Thread.sleep(1000 * 10); + }finally { + lock.writeLock().unlock(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} +``` + +测试代码和结果如下: + +``` + WriteWriteService service = new WriteWriteService(); + Thread a = new Thread(service::write); + a.setName("A"); + Thread b = new Thread(service::write); + b.setName("B"); + + a.start(); + b.start(); + Thread.sleep(1000 * 30); +``` + +结果如下: + +``` +获得写锁A 1485615316519 +获得写锁B 1485615326524 +``` + +两个线程同步执行代码 + +读写互斥的例子: + +``` + public class WriteReadService { + + private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + public void read(){ + try{ + try{ + lock.readLock().lock(); + System.out.println("获得读锁" + Thread.currentThread().getName() + + " " + System.currentTimeMillis()); + Thread.sleep(1000 * 10); + }finally { + lock.readLock().unlock(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + public void write(){ + try{ + try{ + lock.writeLock().lock(); + System.out.println("获得写锁" + Thread.currentThread().getName() + + " " + System.currentTimeMillis()); + Thread.sleep(1000 * 10); + }finally { + lock.writeLock().unlock(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + +} +``` + +测试的代码如下: + +``` + WriteReadService service = new WriteReadService(); + Thread a = new Thread(service::write); + a.setName("A"); + a.start(); + Thread.sleep(1000); + + Thread b = new Thread(service::read); + b.setName("B"); + b.start(); + + Thread.sleep(1000 * 30); +``` + +结果如下: + +``` +获得写锁A 1485615633790 +获得读锁B 1485615643792 +``` + +两个线程读写之间也是同步执行代码。 + +## 总结 +本文介绍了新的同步代码的方式Lock类以及新的等待/通知机制的实现Condition类。本文只是很简单的介绍了他们的概念和使用的方式。关于Condition以及读写锁还有更多的内容,将放在以后的博客中。 \ No newline at end of file diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/ReadReadService.java b/src/main/java/cn/byhieg/threadtutorial/char04/ReadReadService.java new file mode 100644 index 0000000..f1cafe3 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/ReadReadService.java @@ -0,0 +1,27 @@ +package cn.byhieg.threadtutorial.char04; + +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * Created by byhieg on 17/1/28. + * Mail to byhieg@gmail.com + */ +public class ReadReadService { + private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + + public void read(){ + try{ + try{ + lock.readLock().lock(); + System.out.println("获得读锁" + Thread.currentThread().getName() + + " " + System.currentTimeMillis()); + Thread.sleep(1000 * 10); + }finally { + lock.readLock().unlock(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/ReadWriteService.java b/src/main/java/cn/byhieg/threadtutorial/char04/ReadWriteService.java new file mode 100644 index 0000000..52fec70 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/ReadWriteService.java @@ -0,0 +1,42 @@ +package cn.byhieg.threadtutorial.char04; + +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * Created by byhieg on 17/1/28. + * Mail to byhieg@gmail.com + */ +public class ReadWriteService { + private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + public void read(){ + try{ + try{ + lock.readLock().lock(); + System.out.println("获得读锁" + Thread.currentThread().getName() + + " " + System.currentTimeMillis()); + Thread.sleep(1000 * 10); + }finally { + lock.readLock().unlock(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + public void write(){ + try{ + try{ + lock.writeLock().lock(); + System.out.println("获得写锁" + Thread.currentThread().getName() + + " " + System.currentTimeMillis()); + Thread.sleep(1000 * 10); + }finally { + lock.writeLock().unlock(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/ThreadA.java b/src/main/java/cn/byhieg/threadtutorial/char04/ThreadA.java new file mode 100644 index 0000000..eca59b2 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/ThreadA.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorial.char04; + +/** + * Created by byhieg on 17/1/26. + * Mail to byhieg@gmail.com + */ +public class ThreadA extends Thread{ + + private MyConditionMoreService service; + + public ThreadA(MyConditionMoreService service){ + this.service = service; + } + + @Override + public void run() { + service.methodA(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/ThreadB.java b/src/main/java/cn/byhieg/threadtutorial/char04/ThreadB.java new file mode 100644 index 0000000..fa8dfc1 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/ThreadB.java @@ -0,0 +1,20 @@ +package cn.byhieg.threadtutorial.char04; + +/** + * Created by byhieg on 17/1/26. + * Mail to byhieg@gmail.com + */ +public class ThreadB extends Thread{ + + private MyConditionMoreService service; + + public ThreadB(MyConditionMoreService service){ + this.service = service; + } + + @Override + public void run() { + super.run(); + service.methodB(); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/WriteReadService.java b/src/main/java/cn/byhieg/threadtutorial/char04/WriteReadService.java new file mode 100644 index 0000000..802f95c --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/WriteReadService.java @@ -0,0 +1,43 @@ +package cn.byhieg.threadtutorial.char04; + +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * Created by byhieg on 17/1/28. + * Mail to byhieg@gmail.com + */ +public class WriteReadService { + + private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + public void read(){ + try{ + try{ + lock.readLock().lock(); + System.out.println("获得读锁" + Thread.currentThread().getName() + + " " + System.currentTimeMillis()); + Thread.sleep(1000 * 10); + }finally { + lock.readLock().unlock(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + + public void write(){ + try{ + try{ + lock.writeLock().lock(); + System.out.println("获得写锁" + Thread.currentThread().getName() + + " " + System.currentTimeMillis()); + Thread.sleep(1000 * 10); + }finally { + lock.writeLock().unlock(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char04/WriteWriteService.java b/src/main/java/cn/byhieg/threadtutorial/char04/WriteWriteService.java new file mode 100644 index 0000000..dc32b13 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char04/WriteWriteService.java @@ -0,0 +1,26 @@ +package cn.byhieg.threadtutorial.char04; + +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * Created by byhieg on 17/1/28. + * Mail to byhieg@gmail.com + */ +public class WriteWriteService { + private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + public void write(){ + try{ + try{ + lock.writeLock().lock(); + System.out.println("获得写锁" + Thread.currentThread().getName() + + " " +System.currentTimeMillis()); + Thread.sleep(1000 * 10); + }finally { + lock.writeLock().unlock(); + } + }catch (InterruptedException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/more2more/list/Customer.java b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/list/Customer.java new file mode 100644 index 0000000..7a9502c --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/list/Customer.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorial.char05.more2more.list; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Customer implements Runnable { + + private MyQueue queue; + + public Customer(MyQueue queue) { + this.queue = queue; + } + + + @Override + public void run() { + for (;;) { + System.out.println(queue.pop()); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/more2more/list/MyQueue.java b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/list/MyQueue.java new file mode 100644 index 0000000..c66ca47 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/list/MyQueue.java @@ -0,0 +1,46 @@ +package cn.byhieg.threadtutorial.char05.more2more.list; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class MyQueue { + + private List lists = new ArrayList(); + + synchronized public void push(Object element){ + try { + while(lists.size() == 1) { + this.wait(); + } + lists.add(element); + this.notifyAll(); + System.out.println("push = " + lists.size()); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + synchronized public Object pop(){ + Object value = new Object(); + try { + while(lists.size() == 0) { + System.out.println("pop操作中的" + Thread.currentThread().getName() + "呈现wait状态"); + this.wait(); + } + + value = "" + lists.get(0); + lists.remove(0); + this.notifyAll(); + System.out.println("pop=" + lists.size()); + } catch (Exception e) { + e.printStackTrace(); + } + + return value; + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/more2more/list/Producer.java b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/list/Producer.java new file mode 100644 index 0000000..c8f454b --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/list/Producer.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorial.char05.more2more.list; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Producer implements Runnable{ + + private MyQueue queue; + + public Producer(MyQueue queue) { + this.queue = queue; + } + + + @Override + public void run() { + for (;;) { + queue.push(System.currentTimeMillis()); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/more2more/value/Customer.java b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/value/Customer.java new file mode 100644 index 0000000..c2ed08c --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/value/Customer.java @@ -0,0 +1,27 @@ +package cn.byhieg.threadtutorial.char05.more2more.value; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Customer { + + private String lock; + + public Customer(String lock) { + this.lock = lock; + } + + public void getValue() throws InterruptedException{ + synchronized (lock) { + while (ValueObject.value.equals("")){ + System.out.println("消费者 "+ Thread.currentThread().getName() + " WAITING了☆"); + lock.wait(); + } + System.out.println("消费者 " + Thread.currentThread().getName() + " RUNNING了"); + String value = ValueObject.value; + ValueObject.value = ""; + lock.notifyAll(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/more2more/value/Producer.java b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/value/Producer.java new file mode 100644 index 0000000..ba9152f --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/value/Producer.java @@ -0,0 +1,28 @@ +package cn.byhieg.threadtutorial.char05.more2more.value; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Producer { + + private String lock; + + public Producer(String lock) { + this.lock = lock; + } + + public void setValue() throws InterruptedException { + synchronized (lock) { + if (!ValueObject.value.equals("")) { + System.out.println("生产者 " + Thread.currentThread().getName() + " WAITING了★"); + lock.wait(); + } + System.out.println("生产者 " + Thread.currentThread().getName() + " RUNNABLE了"); + String value = System.currentTimeMillis() + "_" + System.nanoTime(); + ValueObject.value = value; + lock.notifyAll(); + } + + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/more2more/value/ValueObject.java b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/value/ValueObject.java new file mode 100644 index 0000000..7fdb260 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/more2more/value/ValueObject.java @@ -0,0 +1,9 @@ +package cn.byhieg.threadtutorial.char05.more2more.value; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class ValueObject { + public static String value = ""; +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/more2one/Customer.java b/src/main/java/cn/byhieg/threadtutorial/char05/more2one/Customer.java new file mode 100644 index 0000000..8224813 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/more2one/Customer.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorial.char05.more2one; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Customer implements Runnable { + + private MyQueue queue; + + public Customer(MyQueue queue) { + this.queue = queue; + } + + + @Override + public void run() { + for (;;) { + System.out.println("取出的数据是" + queue.pop()); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/more2one/MyQueue.java b/src/main/java/cn/byhieg/threadtutorial/char05/more2one/MyQueue.java new file mode 100644 index 0000000..51e2113 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/more2one/MyQueue.java @@ -0,0 +1,46 @@ +package cn.byhieg.threadtutorial.char05.more2one; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class MyQueue { + + private List lists = new ArrayList(); + + synchronized public void push(Object element){ + try { + while(lists.size() == 1) { + this.wait(); + } + lists.add(element); + this.notifyAll(); + System.out.println("push = " + lists.size()); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + synchronized public Object pop(){ + Object value = new Object(); + try { + while(lists.size() == 0) { + System.out.println("pop操作中的" + Thread.currentThread().getName() + "呈现wait状态"); + this.wait(); + } + + value = "" + lists.get(0); + lists.remove(0); + this.notifyAll(); + System.out.println("pop=" + lists.size()); + } catch (Exception e) { + e.printStackTrace(); + } + + return value; + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/more2one/Producer.java b/src/main/java/cn/byhieg/threadtutorial/char05/more2one/Producer.java new file mode 100644 index 0000000..7b803e1 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/more2one/Producer.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorial.char05.more2one; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Producer implements Runnable{ + + private MyQueue queue; + + public Producer(MyQueue queue) { + this.queue = queue; + } + + + @Override + public void run() { + for (;;) { + queue.push(System.currentTimeMillis()); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/one2more/Customer.java b/src/main/java/cn/byhieg/threadtutorial/char05/one2more/Customer.java new file mode 100644 index 0000000..87ceece --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/one2more/Customer.java @@ -0,0 +1,24 @@ +package cn.byhieg.threadtutorial.char05.one2more; + +import cn.byhieg.threadtutorial.char05.one2one.list.*; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Customer implements Runnable { + + private MyQueue queue; + + public Customer(MyQueue queue) { + this.queue = queue; + } + + + @Override + public void run() { + for (;;) { + System.out.println(queue.pop()); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/one2more/MyQueue.java b/src/main/java/cn/byhieg/threadtutorial/char05/one2more/MyQueue.java new file mode 100644 index 0000000..a2eec72 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/one2more/MyQueue.java @@ -0,0 +1,46 @@ +package cn.byhieg.threadtutorial.char05.one2more; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class MyQueue { + + private List lists = new ArrayList(); + + synchronized public void push(Object element){ + try { + while(lists.size() == 1) { + this.wait(); + } + lists.add(element); + this.notifyAll(); + System.out.println("push = " + lists.size()); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + synchronized public Object pop(){ + Object value = new Object(); + try { + while(lists.size() == 0) { + System.out.println("pop操作中的" + Thread.currentThread().getName() + "呈现wait状态"); + this.wait(); + } + + value = "" + lists.get(0); + lists.remove(0); + this.notifyAll(); + System.out.println("pop=" + lists.size()); + } catch (Exception e) { + e.printStackTrace(); + } + + return value; + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/one2more/Producer.java b/src/main/java/cn/byhieg/threadtutorial/char05/one2more/Producer.java new file mode 100644 index 0000000..93709a7 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/one2more/Producer.java @@ -0,0 +1,24 @@ +package cn.byhieg.threadtutorial.char05.one2more; + +import cn.byhieg.threadtutorial.char05.one2one.list.*; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Producer implements Runnable{ + + private MyQueue queue; + + public Producer(MyQueue queue) { + this.queue = queue; + } + + + @Override + public void run() { + for (;;) { + queue.push(System.currentTimeMillis()); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/one2one/list/Customer.java b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/list/Customer.java new file mode 100644 index 0000000..4b83598 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/list/Customer.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorial.char05.one2one.list; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Customer implements Runnable { + + private MyQueue queue; + + public Customer(MyQueue queue) { + this.queue = queue; + } + + + @Override + public void run() { + for (;;) { + System.out.println(queue.pop()); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/one2one/list/MyQueue.java b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/list/MyQueue.java new file mode 100644 index 0000000..31f44be --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/list/MyQueue.java @@ -0,0 +1,46 @@ +package cn.byhieg.threadtutorial.char05.one2one.list; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class MyQueue { + + private List lists = new ArrayList(); + + synchronized public void push(Object element){ + try { + if (lists.size() == 1) { + this.wait(); + } + lists.add(element); + this.notify(); + System.out.println("push = " + lists.size()); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + synchronized public Object pop(){ + Object value = new Object(); + try { + if (lists.size() == 0) { + System.out.println("pop操作中的" + Thread.currentThread().getName() + "呈现wait状态"); + this.wait(); + } + + value = "" + lists.get(0); + lists.remove(0); + this.notify(); + System.out.println("pop=" + lists.size()); + } catch (Exception e) { + e.printStackTrace(); + } + + return value; + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/one2one/list/Producer.java b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/list/Producer.java new file mode 100644 index 0000000..6dbacef --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/list/Producer.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorial.char05.one2one.list; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Producer implements Runnable{ + + private MyQueue queue; + + public Producer(MyQueue queue) { + this.queue = queue; + } + + + @Override + public void run() { + for (;;) { + queue.push(System.currentTimeMillis()); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/one2one/value/Customer.java b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/value/Customer.java new file mode 100644 index 0000000..b4c3b52 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/value/Customer.java @@ -0,0 +1,26 @@ +package cn.byhieg.threadtutorial.char05.one2one.value; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Customer { + + private String lock; + + public Customer(String lock) { + this.lock = lock; + } + + public void getValue() throws InterruptedException{ + synchronized (lock) { + if (ValueObject.value.equals("")){ + lock.wait(); + } + String value = ValueObject.value; + ValueObject.value = ""; + System.out.println("取到的值" + value); + lock.notify(); + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/one2one/value/Producer.java b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/value/Producer.java new file mode 100644 index 0000000..7b11902 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/value/Producer.java @@ -0,0 +1,27 @@ +package cn.byhieg.threadtutorial.char05.one2one.value; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class Producer { + + private String lock; + + public Producer(String lock) { + this.lock = lock; + } + + public void setValue() throws InterruptedException { + synchronized (lock) { + if (!ValueObject.value.equals("")) { + lock.wait(); + } + String value = System.currentTimeMillis() + "_" + System.nanoTime(); + System.out.println("set的值 " + value); + ValueObject.value = value; + lock.notify(); + } + + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/char05/one2one/value/ValueObject.java b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/value/ValueObject.java new file mode 100644 index 0000000..69bb18e --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/char05/one2one/value/ValueObject.java @@ -0,0 +1,9 @@ +package cn.byhieg.threadtutorial.char05.one2one.value; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class ValueObject { + public static String value = ""; +} diff --git a/src/main/java/cn/byhieg/threadtutorial/concurrent/atom/AtomFactory.java b/src/main/java/cn/byhieg/threadtutorial/concurrent/atom/AtomFactory.java new file mode 100644 index 0000000..f5da772 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/concurrent/atom/AtomFactory.java @@ -0,0 +1,36 @@ +package cn.byhieg.threadtutorial.concurrent.atom; + +import java.util.concurrent.atomic.*; + +/** + * Created by shiqifeng on 2017/5/5. + * Mail byhieg@gmail.com + */ +public class AtomFactory { + + private static final AtomFactory atomFactory = new AtomFactory(); + + private AtomFactory(){ + + } + + public static AtomFactory getInstance(){ + return atomFactory; + } + + public AtomicInteger createAtomInt(int a){ + return new AtomicInteger(a); + } + + public AtomicIntegerArray createAtomArray(int[] a) { + return new AtomicIntegerArray(a); + } + + public AtomicReference createAtomReference(MyObject object){ + return new AtomicReference<>(); + } + + public AtomicIntegerFieldUpdater createAtomIntegerUpdate(String fieldName) { + return AtomicIntegerFieldUpdater.newUpdater(MyObject.class, fieldName); + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/concurrent/atom/MyObject.java b/src/main/java/cn/byhieg/threadtutorial/concurrent/atom/MyObject.java new file mode 100644 index 0000000..69ebbb6 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/concurrent/atom/MyObject.java @@ -0,0 +1,12 @@ +package cn.byhieg.threadtutorial.concurrent.atom; + +/** + * Created by shiqifeng on 2017/5/5. + * Mail byhieg@gmail.com + */ +public class MyObject { + + public String name = "byhieg"; + public int age = 24; + public volatile int id = 1; +} diff --git a/src/main/java/cn/byhieg/threadtutorial/concurrent/blocking/ArrayBlock.java b/src/main/java/cn/byhieg/threadtutorial/concurrent/blocking/ArrayBlock.java new file mode 100644 index 0000000..3687b31 --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/concurrent/blocking/ArrayBlock.java @@ -0,0 +1,34 @@ +package cn.byhieg.threadtutorial.concurrent.blocking; + +import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer; + +import javax.sound.midi.SoundbankResource; +import java.lang.management.LockInfo; +import java.util.concurrent.*; + +/** + * Created by byhieg on 17/5/3. + * Mail to byhieg@gmail.com + */ +public class ArrayBlock { + + private BlockingQueue blockingQueue; + + public ArrayBlock(int index) { + switch (index) { + case 0: + blockingQueue = new ArrayBlockingQueue(3); + break; + case 1: + blockingQueue = new LinkedBlockingQueue<>(); + break; + case 2: + blockingQueue = new SynchronousQueue<>(); + break; + } + } + + public BlockingQueue getBlockingQueue() { + return blockingQueue; + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/concurrent/blocking/Costumer.java b/src/main/java/cn/byhieg/threadtutorial/concurrent/blocking/Costumer.java new file mode 100644 index 0000000..f88b45f --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/concurrent/blocking/Costumer.java @@ -0,0 +1,31 @@ +package cn.byhieg.threadtutorial.concurrent.blocking; + +import java.util.concurrent.BlockingQueue; + +/** + * Created by byhieg on 17/5/3. + * Mail to byhieg@gmail.com + */ +public class Costumer extends Thread{ + + private BlockingQueue blockingQueue; + + public Costumer(ArrayBlock arrayBlock) { + blockingQueue = arrayBlock.getBlockingQueue(); + this.setName("Costumer"); + } + + @Override + public void run() { + super.run(); + while (true) { + try { + Thread.sleep(5000); + String str = blockingQueue.take(); + System.out.println(getName() + " 取出数据 " + str); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/cn/byhieg/threadtutorial/concurrent/blocking/Producer.java b/src/main/java/cn/byhieg/threadtutorial/concurrent/blocking/Producer.java new file mode 100644 index 0000000..a2d12eb --- /dev/null +++ b/src/main/java/cn/byhieg/threadtutorial/concurrent/blocking/Producer.java @@ -0,0 +1,29 @@ +package cn.byhieg.threadtutorial.concurrent.blocking; + +import java.util.concurrent.BlockingQueue; + +/** + * Created by byhieg on 17/5/3. + * Mail to byhieg@gmail.com + */ +public class Producer extends Thread { + + private BlockingQueue blockingQueue; + @Override + public void run() { + super.run(); + for (int i = 0 ; i < 5;i++) { + try { + blockingQueue.put(i + ""); + System.out.println(getName() + " 生产数据"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public Producer(ArrayBlock arrayBlock){ + this.setName("Producer"); + blockingQueue = arrayBlock.getBlockingQueue(); + } +} diff --git a/src/test/java/cn/byhieg/algorithmtutorialtest/BinaryTreeTest.java b/src/test/java/cn/byhieg/algorithmtutorialtest/BinaryTreeTest.java new file mode 100644 index 0000000..9c1cfa5 --- /dev/null +++ b/src/test/java/cn/byhieg/algorithmtutorialtest/BinaryTreeTest.java @@ -0,0 +1,88 @@ +package cn.byhieg.algorithmtutorialtest; + +import cn.byhieg.algorithmtutorial.BinaryTree; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/4/15. + * Mail to byhieg@gmail.com + */ +public class BinaryTreeTest extends TestCase { + + BinaryTree.Node root = new BinaryTree.Node(1); + public void setUp() throws Exception { + super.setUp(); + BinaryTree.Node[] nodes = new BinaryTree.Node[10]; + nodes[0] = new BinaryTree.Node(2); + root.left = nodes[0]; + for (int i = 1 ; i < 10;i++) { + nodes[i] = new BinaryTree.Node(2 + i); + if (i % 2 == 0){ + nodes[i - 1].left = nodes[i]; + }else{ + nodes[i - 1].right = nodes[i]; + } + } + + } + + public void tearDown() throws Exception { + System.out.println(); + } + + public void testPreOrder1() throws Exception { + System.out.println("递归的先续遍历"); + BinaryTree.preOrder1(root); + } + + public void testPreOrder2() throws Exception { + System.out.println("非递归的先续遍历"); + BinaryTree.preOrder2(root); + } + + + public void testInOrder1() throws Exception { + System.out.println("递归的中序遍历"); + BinaryTree.inOrder1(root); + } + + public void testInOrder2() throws Exception { + System.out.println("非递归的中序遍历"); + BinaryTree.inOrder2(root); + } + + public void testPostOrder1() throws Exception { + System.out.println("递归的后续遍历"); + BinaryTree.postOrder1(root); + } + + public void testPostOrder2() throws Exception { + System.out.println("非递归的后续遍历"); + BinaryTree.postOrder2(root); + } + + public void testLevelOrder() throws Exception { + System.out.println("层次遍历"); + BinaryTree.levelOrder(root); + } + + public void testGetNodes() throws Exception { + System.out.print("节点数" + BinaryTree.getNodes(root)); + } + + public void testGetLeafs() throws Exception { + System.out.print("叶子数" + BinaryTree.getLeafs(root)); + } + + public void testGetHeight() throws Exception { + System.out.print("树的高度" + BinaryTree.getHeight(root)); + } + + public void testCalcKNodes() throws Exception { + System.out.print("第2层的节点数" + BinaryTree.calcKNodes(root,2)); + } + + public void testMirror() throws Exception { + BinaryTree.mirror(root); + } +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/algorithmtutorialtest/FindTest.java b/src/test/java/cn/byhieg/algorithmtutorialtest/FindTest.java new file mode 100644 index 0000000..53914a9 --- /dev/null +++ b/src/test/java/cn/byhieg/algorithmtutorialtest/FindTest.java @@ -0,0 +1,34 @@ +package cn.byhieg.algorithmtutorialtest; + +import cn.byhieg.algorithmtutorial.Find; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/3/29. + * Mail byhieg@gmail.com + */ +public class FindTest extends TestCase { + int[] nums; + int result; + public void setUp() throws Exception { + super.setUp(); + nums = new int[]{}; + } + + public void tearDown() throws Exception { + System.out.println(result); + } + + public void testBinarySerachFind() throws Exception { + result = new Find().binarySearchFind(nums,2); + } + +// public void testBinarySearchMinFind() throws Exception { +// result = new Find().binarySearchMinFind(nums,1); +// } + +// public void testBinarySearchMaxFind() throws Exception { +// result = new Find().binarySearchMaxFind(nums, 2); +// } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/algorithmtutorialtest/GraphMatrixTest.java b/src/test/java/cn/byhieg/algorithmtutorialtest/GraphMatrixTest.java new file mode 100644 index 0000000..1851a18 --- /dev/null +++ b/src/test/java/cn/byhieg/algorithmtutorialtest/GraphMatrixTest.java @@ -0,0 +1,56 @@ +package cn.byhieg.algorithmtutorialtest; + +import cn.byhieg.algorithmtutorial.GraphMatrix; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/4/5. + * Mail byhieg@gmail.com + */ +public class GraphMatrixTest extends TestCase { + + GraphMatrix graphMatrix; + GraphMatrix.Weight[][] weights; + public void setUp() throws Exception { + super.setUp(); + weights = new GraphMatrix.Weight[5][5]; + for (int i = 0 ; i < weights.length;i++) + for (int j = 0 ; j < weights[i].length;j++){ + weights[i][j] = new GraphMatrix.Weight(); + weights[j][i] = new GraphMatrix.Weight(); + } + + weights[0][1] = new GraphMatrix.Weight(100); + weights[1][2] = new GraphMatrix.Weight(10); + weights[2][3] = new GraphMatrix.Weight(20); + weights[3][1] = new GraphMatrix.Weight(25); + weights[2][4] = new GraphMatrix.Weight(20); + + weights[1][0] = new GraphMatrix.Weight(100); + weights[2][1] = new GraphMatrix.Weight(10); + weights[3][2] = new GraphMatrix.Weight(20); + weights[1][3] = new GraphMatrix.Weight(25); + weights[4][2] = new GraphMatrix.Weight(20); + + + graphMatrix = new GraphMatrix(weights); + } + + public void tearDown() throws Exception { + + } + + public void testBFS() throws Exception { + graphMatrix.BFS(4); + + } + + public void testDFS() throws Exception { + graphMatrix.DFS(0); + } + + public void testDijkstra() throws Exception { + graphMatrix.dijkstra(1,2); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/algorithmtutorialtest/SingleLinkListTest.java b/src/test/java/cn/byhieg/algorithmtutorialtest/SingleLinkListTest.java new file mode 100644 index 0000000..e7f2145 --- /dev/null +++ b/src/test/java/cn/byhieg/algorithmtutorialtest/SingleLinkListTest.java @@ -0,0 +1,69 @@ +package cn.byhieg.algorithmtutorialtest; + +import cn.byhieg.algorithmtutorial.SingleLinkList; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/5/2. + * Mail to byhieg@gmail.com + */ +public class SingleLinkListTest extends TestCase { + + + SingleLinkList linkList; + + public void setUp() throws Exception { + super.setUp(); + linkList = new SingleLinkList(); + } + + public void tearDown() throws Exception { +// linkList.printLinkList(linkList.head); +// System.out.println(); + } + + + public void testInsertFromTail() throws Exception { +// linkList.insertFromTail(1); +// linkList.insertFromTail(2); +// linkList.insertFromTail(3); +// linkList.insertFromTail(4); +// linkList.insertFromTail(5); +// linkList.insertFromTail(6); +// System.out.println("尾插入"); + } + + public void testInsertFromHead() throws Exception { +// linkList.insertFromHead(1); +// linkList.insertFromHead(2); +// linkList.insertFromHead(3); +// linkList.insertFromHead(4); +// linkList.insertFromHead(5); +// linkList.insertFromHead(6); +// System.out.println("头插入"); + } + public void testReverseLinkList() throws Exception { + System.out.println(); + linkList.insertFromHead(1); + linkList.insertFromHead(2); + linkList.insertFromHead(3); + linkList.insertFromHead(4); + linkList.insertFromHead(5); + linkList.insertFromHead(6); + linkList.printLinkList(linkList.reverseLinkList()); + } + + public void testReverseLinkList2() throws Exception{ + System.out.println("递归反转链表"); + linkList.insertFromHead(1); + linkList.insertFromHead(2); + linkList.insertFromHead(3); + linkList.insertFromHead(4); + linkList.insertFromHead(5); + linkList.insertFromHead(6); + linkList.printLinkList(linkList.reverseLinkList(linkList.getHead())); + } + public void testGetHead() throws Exception { + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/algorithmtutorialtest/SortTest.java b/src/test/java/cn/byhieg/algorithmtutorialtest/SortTest.java new file mode 100644 index 0000000..046daca --- /dev/null +++ b/src/test/java/cn/byhieg/algorithmtutorialtest/SortTest.java @@ -0,0 +1,53 @@ +package cn.byhieg.algorithmtutorialtest; + +import cn.byhieg.algorithmtutorial.Sort; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/3/28. + * Mail byhieg@gmail.com + */ +public class SortTest extends TestCase { + int [] nums; + public void setUp() throws Exception { + super.setUp(); + nums = new int[]{10, 20, 2, 3, 1, 100, 45, 22, 51, 21}; + } + + public void tearDown() throws Exception { + for (int i = 0 ; i < nums.length;i++){ + System.out.print(nums[i] + " "); + } + } +// +// public void testChooseSort() throws Exception { +// new Sort().chooseSort(nums); +// } +// +// +// public void testInsertDirectlySort() throws Exception { +// new Sort().insertDirectlySort(nums); +// } +// +// public void testInsertBinarySort() throws Exception { +// new Sort().insertBinarySort(nums); +// } +// +// public void testBubbleSort() throws Exception { +// new Sort().bubbleSort2(nums); +// } +// +// public void testQuickSort() throws Exception { +// new Sort().quickSort(nums); +// } + +// public void testHeapSort() throws Exception { +// new Sort().heapSort(nums); +// } + + public void testMergeSort() throws Exception { + new Sort().mergeSort(nums); + + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/annotationstutorialtest/AConstructorProcessTest.java b/src/test/java/cn/byhieg/annotationstutorialtest/AConstructorProcessTest.java new file mode 100644 index 0000000..74c7b6b --- /dev/null +++ b/src/test/java/cn/byhieg/annotationstutorialtest/AConstructorProcessTest.java @@ -0,0 +1,18 @@ +package cn.byhieg.annotationstutorialtest; + +import cn.byhieg.annotationstutorial.AConstructorProcess; +import cn.byhieg.annotationstutorial.User; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/2/14. + * Mail to byhieg@gmail.com + */ +public class AConstructorProcessTest extends TestCase { + public void testInit() throws Exception { + User user = new User(); + AConstructorProcess.init(user); + System.out.println(user.toString()); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/annotationstutorialtest/AMethodProcessTest.java b/src/test/java/cn/byhieg/annotationstutorialtest/AMethodProcessTest.java new file mode 100644 index 0000000..281d968 --- /dev/null +++ b/src/test/java/cn/byhieg/annotationstutorialtest/AMethodProcessTest.java @@ -0,0 +1,16 @@ +package cn.byhieg.annotationstutorialtest; + +import cn.byhieg.annotationstutorial.AMethodProcess; +import cn.byhieg.annotationstutorial.User; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/2/14. + * Mail to byhieg@gmail.com + */ +public class AMethodProcessTest extends TestCase { + public void testInitMethod() throws Exception { + AMethodProcess.initMethod(new User()); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/bitoperatetutorialtest/BitOperateTest.java b/src/test/java/cn/byhieg/bitoperatetutorialtest/BitOperateTest.java new file mode 100644 index 0000000..962eccd --- /dev/null +++ b/src/test/java/cn/byhieg/bitoperatetutorialtest/BitOperateTest.java @@ -0,0 +1,23 @@ +package cn.byhieg.bitoperatetutorialtest; + +import cn.byhieg.bitoperatetutorial.BitOperate; +import junit.framework.TestCase; + +/** + * Created by byhieg on 2017/6/27. + * Mail to byhieg@gmail.com + */ +public class BitOperateTest extends TestCase { + + BitOperate bitOperate; + @Override + protected void setUp() throws Exception { + super.setUp(); + bitOperate = new BitOperate(); + } + + public void testGetRightestOne() throws Exception { + assertEquals(bitOperate.getRightestOne(Integer.valueOf("100100",2)),"100"); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/collectiontutorialtest/ArrayListDemoTest.java b/src/test/java/cn/byhieg/collectiontutorialtest/ArrayListDemoTest.java new file mode 100644 index 0000000..3d5407b --- /dev/null +++ b/src/test/java/cn/byhieg/collectiontutorialtest/ArrayListDemoTest.java @@ -0,0 +1,32 @@ +package cn.byhieg.collectiontutorialtest; + +import cn.byhieg.collectiontutorial.listtutorial.ArrayListDemo; +import junit.framework.TestCase; +import java.util.Iterator; + +/** + * Created by byhieg on 17/2/7. + * Mail to byhieg@gmail.com + */ +public class ArrayListDemoTest extends TestCase { + + + public void testList() throws Exception{ + ArrayListDemo demo = new ArrayListDemo(); + for (int i = 0 ;i < 10 ; i++){ + demo.getListA().add(i); + } + Iterator iteratorA = demo.getListA().iterator(); + while (iteratorA.hasNext()) { + System.out.println(iteratorA.next()); + } + + demo.setListC(demo.getListA()); + Iterator iteratorC = demo.getListC().iterator(); + while (iteratorC.hasNext()) { + System.out.println(iteratorC.next()); + } + + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/collectiontutorialtest/BinarySearchTreeTest.java b/src/test/java/cn/byhieg/collectiontutorialtest/BinarySearchTreeTest.java new file mode 100644 index 0000000..c56ce25 --- /dev/null +++ b/src/test/java/cn/byhieg/collectiontutorialtest/BinarySearchTreeTest.java @@ -0,0 +1,64 @@ +package cn.byhieg.collectiontutorialtest; + +import cn.byhieg.algorithmtutorial.BinarySearchTree; +import junit.framework.TestCase; +import org.junit.Assert; + +/** + * Created by byhieg on 17/3/30. + * Mail to byhieg@gmail.com + */ +public class BinarySearchTreeTest extends TestCase { + int[] nums; + BinarySearchTree tree; + + public void setUp() throws Exception { + super.setUp(); + nums = new int[]{1,2,3,4,5}; + tree = new BinarySearchTree(nums); + } + + public void tearDown() throws Exception { + BinarySearchTree.Node node = new BinarySearchTree.Node(10); + tree.levelRead(node); + } + + + public void testInsert() throws Exception { + } + + public void testInOrder() throws Exception { + System.out.println("中序遍历"); + tree.inorder2(tree.getRoot()); + System.out.println(); + } + + public void testPreOrder() throws Exception { + System.out.println("先续遍历"); + tree.preOrder2(tree.getRoot()); + System.out.println(); + } + + public void testPostOrder() throws Exception { + System.out.println("后续遍历"); + tree.postOrder2(tree.getRoot()); + System.out.println(); + } + + public void testGetTree() throws Exception { + System.out.println("树"); + int[] pre = new int[]{1,2,4,5,3}; + int[] in = new int[]{4,2,5,1,3}; + BinarySearchTree.Node node = new BinarySearchTree.Node(1); + tree.getTree(pre, in,node); + tree.levelRead(node); + } + +// public void testGetMaxData() throws Exception { +// Assert.assertEquals(10,tree.getMaxNode().data); +// } +// +// public void testGetMinData() throws Exception { +// Assert.assertEquals(1,tree.getMinNode().data); +// } +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/collectiontutorialtest/HashMapExampleTest.java b/src/test/java/cn/byhieg/collectiontutorialtest/HashMapExampleTest.java new file mode 100644 index 0000000..bdbb2d7 --- /dev/null +++ b/src/test/java/cn/byhieg/collectiontutorialtest/HashMapExampleTest.java @@ -0,0 +1,24 @@ +package cn.byhieg.collectiontutorialtest; + +import cn.byhieg.collectiontutorial.maptutorial.HashMapExample; +import junit.framework.TestCase; + +import java.util.Map; + +/** + * Created by byhieg on 17/2/25. + * Mail to byhieg@gmail.com + */ +public class HashMapExampleTest extends TestCase { + HashMapExample example = new HashMapExample(); + public void testInsertMap() throws Exception { + Map maps = example.insertMap(); + example.getAllKeyAndValue(maps); + } + + public void testGetValue() throws Exception { + + } + + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/collectiontutorialtest/LinkedHashMapExampleTest.java b/src/test/java/cn/byhieg/collectiontutorialtest/LinkedHashMapExampleTest.java new file mode 100644 index 0000000..47f0085 --- /dev/null +++ b/src/test/java/cn/byhieg/collectiontutorialtest/LinkedHashMapExampleTest.java @@ -0,0 +1,19 @@ +package cn.byhieg.collectiontutorialtest; + +import cn.byhieg.collectiontutorial.maptutorial.LinkedHashMapExample; +import junit.framework.TestCase; + +import java.util.LinkedHashMap; + +/** + * Created by byhieg on 17/2/25. + * Mail to byhieg@gmail.com + */ +public class LinkedHashMapExampleTest extends TestCase { + LinkedHashMapExample example = new LinkedHashMapExample(); + public void testInsertMap() throws Exception { + LinkedHashMap map = example.insertMap(); + example.printMaps(map); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/collectiontutorialtest/LinkedListDemoTest.java b/src/test/java/cn/byhieg/collectiontutorialtest/LinkedListDemoTest.java new file mode 100644 index 0000000..290f22a --- /dev/null +++ b/src/test/java/cn/byhieg/collectiontutorialtest/LinkedListDemoTest.java @@ -0,0 +1,19 @@ +package cn.byhieg.collectiontutorialtest; + +import cn.byhieg.collectiontutorial.listtutorial.LinkedListDemo; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/2/15. + * Mail to byhieg@gmail.com + */ +public class LinkedListDemoTest extends TestCase { + + public void testList() throws Exception { + LinkedListDemo demo = new LinkedListDemo(); + demo.getList().add(111); + System.out.println(demo.getList().get(0)); + demo.getList().remove(0); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/collectiontutorialtest/SimpleArrayListTest.java b/src/test/java/cn/byhieg/collectiontutorialtest/SimpleArrayListTest.java new file mode 100644 index 0000000..7be8acd --- /dev/null +++ b/src/test/java/cn/byhieg/collectiontutorialtest/SimpleArrayListTest.java @@ -0,0 +1,25 @@ +package cn.byhieg.collectiontutorialtest; + +import cn.byhieg.collectiontutorial.listtutorial.SimpleArrayList; +import junit.framework.TestCase; + +import java.util.ArrayList; + +/** + * Created by byhieg on 17/2/7. + * Mail to byhieg@gmail.com + */ +public class SimpleArrayListTest extends TestCase { + public void testAdd() throws Exception { + SimpleArrayList list = new SimpleArrayList<>(); + for (int i = 0 ; i < 20 ; i++){ + list.add(i); + } + + list.remove(1); + for (int i = 0 ; i < list.size(); i++) { + System.out.println(list.get(i)); + } + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/collectiontutorialtest/SimpleLinkedListTest.java b/src/test/java/cn/byhieg/collectiontutorialtest/SimpleLinkedListTest.java new file mode 100644 index 0000000..ba9ad9f --- /dev/null +++ b/src/test/java/cn/byhieg/collectiontutorialtest/SimpleLinkedListTest.java @@ -0,0 +1,46 @@ +package cn.byhieg.collectiontutorialtest; + +import cn.byhieg.collectiontutorial.listtutorial.SimpleArrayList; +import cn.byhieg.collectiontutorial.listtutorial.SimpleLinkedList; +import junit.framework.TestCase; + +import java.net.SocketImpl; + +/** + * Created by byhieg on 17/2/15. + * Mail to byhieg@gmail.com + */ +public class SimpleLinkedListTest extends TestCase { + public void testAdd() throws Exception { + new SimpleArrayList().add(11111); + } + + public void testAdd1() throws Exception { + new SimpleArrayList().add(0,10); + } + + public void testGet() throws Exception { + SimpleLinkedList lists = new SimpleLinkedList<>(); + lists.add("byhieg"); + System.out.println(lists.get(0)); + } + + public void testIndexOf() throws Exception { + SimpleLinkedList lists = new SimpleLinkedList<>(); + lists.add(1); + System.out.println(lists.indexOf(1)); + } + + public void testRemove() throws Exception { + SimpleLinkedList lists = new SimpleLinkedList<>(); + lists.add(111); + lists.add(1231); + lists.add(1513); + for (int i = 0 ; i < lists.size();i++) { + System.out.println(lists.get(i)); + } + + lists.remove(1); + System.out.println(lists.get(1)); + } +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/collectiontutorialtest/TreeMapExampleTest.java b/src/test/java/cn/byhieg/collectiontutorialtest/TreeMapExampleTest.java new file mode 100644 index 0000000..0fdd004 --- /dev/null +++ b/src/test/java/cn/byhieg/collectiontutorialtest/TreeMapExampleTest.java @@ -0,0 +1,45 @@ +package cn.byhieg.collectiontutorialtest; + +import cn.byhieg.collectiontutorial.maptutorial.TreeMapExample; +import junit.framework.TestCase; + +import java.util.TreeMap; + +/** + * Created by byhieg on 17/2/25. + * Mail to byhieg@gmail.com + */ +public class TreeMapExampleTest extends TestCase { + TreeMapExample example = new TreeMapExample(); + TreeMap maps = example.insertMap(); + + public void testGetSmallestEntry() throws Exception { + example.getSmallestEntry(maps); + } + + public void testGetLargestEntry() throws Exception { + example.getLargestEntry(maps); + } + + public void testGetHigherEntry() throws Exception { + example.getHigherEntry(maps,"2"); + } + + public void testGetLowestEntry() throws Exception { + example.getLowestEntry(maps,"2"); + } + + public void testGetRangeMap() throws Exception { + example.getRangeMap(maps,"2","8"); + + } + + public void testGetHeadMap() throws Exception { + example.getHeadMap(maps,"4",true); + } + + public void testGetTailMap() throws Exception { + example.getTailMap(maps,"7",true); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/designpatterntutorialtest/BuilderTest.java b/src/test/java/cn/byhieg/designpatterntutorialtest/BuilderTest.java new file mode 100644 index 0000000..2a67a00 --- /dev/null +++ b/src/test/java/cn/byhieg/designpatterntutorialtest/BuilderTest.java @@ -0,0 +1,16 @@ +package cn.byhieg.designpatterntutorialtest; + +import cn.byhieg.designpatterntutorial.builder.Person; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/5/7. + * Mail byhieg@gmail.com + */ +public class BuilderTest extends TestCase { + public void testBuild() throws Exception { + Person person = new Person.Builder().setAge(24).setHeight(178).setName("byhieg").setWeight(80).build(); + System.out.println(person.toString()); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/designpatterntutorialtest/SimpleDialogTest.java b/src/test/java/cn/byhieg/designpatterntutorialtest/SimpleDialogTest.java new file mode 100644 index 0000000..002115a --- /dev/null +++ b/src/test/java/cn/byhieg/designpatterntutorialtest/SimpleDialogTest.java @@ -0,0 +1,18 @@ +package cn.byhieg.designpatterntutorialtest; + +import cn.byhieg.designpatterntutorial.builder.SimpleDialog; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/5/7. + * Mail byhieg@gmail.com + */ +public class SimpleDialogTest extends TestCase { + + public void testBuilder() throws Exception { + SimpleDialog dialog = new SimpleDialog.Builder().setIcon("图标").setMessage("这是Dialog").setPositiveButton("确认").setNegativeButton("否定").create(); + + + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/iotutorialtest/BufferdInputStreamExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/BufferdInputStreamExampleTest.java new file mode 100644 index 0000000..7f8afbd --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/BufferdInputStreamExampleTest.java @@ -0,0 +1,15 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.bytestreamio.BufferdInputStreamExample; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class BufferdInputStreamExampleTest extends TestCase { + public void testReadFromFile() throws Exception { + new BufferdInputStreamExample().readFromFile(); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/iotutorialtest/BufferdOutputStreamExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/BufferdOutputStreamExampleTest.java new file mode 100644 index 0000000..dbecd71 --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/BufferdOutputStreamExampleTest.java @@ -0,0 +1,16 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.bytestreamio.BufferdOutputStreamExample; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class BufferdOutputStreamExampleTest extends TestCase { + public void testWriteToFile() throws Exception { + new BufferdOutputStreamExample().writeToFile(); + + } + +} diff --git a/src/test/java/cn/byhieg/iotutorialtest/BufferedReaderExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/BufferedReaderExampleTest.java new file mode 100644 index 0000000..a8f4add --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/BufferedReaderExampleTest.java @@ -0,0 +1,15 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.charsetstreamio.BufferedReaderExample; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class BufferedReaderExampleTest extends TestCase { + public void testReadFromFile() throws Exception { + new BufferedReaderExample().readFromFile(); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/iotutorialtest/BufferedWriterExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/BufferedWriterExampleTest.java new file mode 100644 index 0000000..2f67683 --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/BufferedWriterExampleTest.java @@ -0,0 +1,17 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.charsetstreamio.BufferedWriterExample; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class BufferedWriterExampleTest extends TestCase { + public void testWriteToFile() throws Exception { + + new BufferedWriterExample().writeToFile(); + + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/iotutorialtest/ByteArrayInputStreamExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/ByteArrayInputStreamExampleTest.java new file mode 100644 index 0000000..06953db --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/ByteArrayInputStreamExampleTest.java @@ -0,0 +1,25 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.bytestreamio.ByteArrayInputStreamExample; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/2/21. + * Mail to byhieg@gmail.com + */ +public class ByteArrayInputStreamExampleTest extends TestCase { + public void testReadFromArray() throws Exception { + byte[] bytes = new byte[]{0x1,0x2,0x3,0x4,0x5,0x6,0x7}; + ByteArrayInputStreamExample example = new ByteArrayInputStreamExample(); + System.out.println(example.readFromArray(bytes)); + } + + + public void testReadMarkAndReset() throws Exception { + byte[] bytes = new byte[]{0x1,0x2,0x3,0x4,0x5,0x6,0x7}; + ByteArrayInputStreamExample example = new ByteArrayInputStreamExample(); + example.readMarkAndReset(bytes,2); + System.out.println("++++++++++++++++++++"); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/iotutorialtest/ByteArrayOutPutStreamExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/ByteArrayOutPutStreamExampleTest.java new file mode 100644 index 0000000..2d13943 --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/ByteArrayOutPutStreamExampleTest.java @@ -0,0 +1,15 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.bytestreamio.ByteArrayOutPutStreamExample; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class ByteArrayOutPutStreamExampleTest extends TestCase { + public void testWriteFromFile() throws Exception { + new ByteArrayOutPutStreamExample().writeToBytes(); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/iotutorialtest/FileInputStreamExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/FileInputStreamExampleTest.java new file mode 100644 index 0000000..c52199e --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/FileInputStreamExampleTest.java @@ -0,0 +1,16 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.bytestreamio.FileInputStreamExample; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class FileInputStreamExampleTest extends TestCase { + + public void testReadFromFile() throws Exception { + new FileInputStreamExample().readFromFile(); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/iotutorialtest/FileOutputStreamExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/FileOutputStreamExampleTest.java new file mode 100644 index 0000000..d814cee --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/FileOutputStreamExampleTest.java @@ -0,0 +1,31 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.bytestreamio.FileOutputStreamExample; +import junit.framework.TestCase; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class FileOutputStreamExampleTest extends TestCase { + public void testWriteToFile() throws Exception { + new FileOutputStreamExample().writeToFile(); + String s = File.separator; + try (FileInputStream fis = new FileInputStream("D:" + s + "write_file.txt")) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] bytes = new byte[1024]; + while (fis.read(bytes) != -1) { + baos.write(bytes); + } + + System.out.println(baos.toString()); + } + + + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/iotutorialtest/FileReaderExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/FileReaderExampleTest.java new file mode 100644 index 0000000..ecad4af --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/FileReaderExampleTest.java @@ -0,0 +1,15 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.charsetstreamio.FileReaderExample; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class FileReaderExampleTest extends TestCase { + public void testReadFromFile() throws Exception { + new FileReaderExample().readFromFile(); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/iotutorialtest/FileWriterExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/FileWriterExampleTest.java new file mode 100644 index 0000000..5b21731 --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/FileWriterExampleTest.java @@ -0,0 +1,15 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.charsetstreamio.FileWriterExample; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class FileWriterExampleTest extends TestCase { + public void testWriteToFile() throws Exception { + new FileWriterExample().writeToFile(); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/iotutorialtest/InputStreamReaderExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/InputStreamReaderExampleTest.java new file mode 100644 index 0000000..c39f35f --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/InputStreamReaderExampleTest.java @@ -0,0 +1,15 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.charsetstreamio.InputStreamReaderExample; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class InputStreamReaderExampleTest extends TestCase { + public void testReadFromFile() throws Exception { + new InputStreamReaderExample().readFromFile(); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/iotutorialtest/OutputStreamWriterExampleTest.java b/src/test/java/cn/byhieg/iotutorialtest/OutputStreamWriterExampleTest.java new file mode 100644 index 0000000..64a719d --- /dev/null +++ b/src/test/java/cn/byhieg/iotutorialtest/OutputStreamWriterExampleTest.java @@ -0,0 +1,16 @@ +package cn.byhieg.iotutorialtest; + +import cn.byhieg.iotutorial.charsetstreamio.OutputStreamWriterExample; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/2/23. + * Mail byhieg@gmail.com + */ +public class OutputStreamWriterExampleTest extends TestCase { + + public void testWriteToFile() throws Exception { + new OutputStreamWriterExample().writeToFile(); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/reflectiontutorialtest/AnnotationObjectTest.java b/src/test/java/cn/byhieg/reflectiontutorialtest/AnnotationObjectTest.java new file mode 100644 index 0000000..8a5ae2b --- /dev/null +++ b/src/test/java/cn/byhieg/reflectiontutorialtest/AnnotationObjectTest.java @@ -0,0 +1,66 @@ +package cn.byhieg.reflectiontutorialtest; + +import cn.byhieg.reflectiontutorial.AnnotationObject; +import cn.byhieg.reflectiontutorial.MyAnnotation; +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * Created by byhieg on 17/1/9. + * Mail to byhieg@gmail.com + */ +public class AnnotationObjectTest extends TestCase { + + public void testAnnotation() throws Exception{ + Class clz = AnnotationObject.class; + Annotation[] annotationsInClass = clz.getAnnotations(); + for (Annotation annotation : annotationsInClass){ + if (annotation instanceof MyAnnotation){ + MyAnnotation myAnnotation = (MyAnnotation)annotation; + System.out.println("name: " + myAnnotation.name()); + System.out.println("value:" + myAnnotation.value()); + } + } + + Method method = clz.getMethod("doSomeThing"); + Annotation[] annotationsInMethod = method.getDeclaredAnnotations(); + for (Annotation annotation : annotationsInMethod){ + if (annotation instanceof MyAnnotation){ + MyAnnotation myAnnotation = (MyAnnotation)annotation; + System.out.println("name: " + myAnnotation.name()); + System.out.println("value:" + myAnnotation.value()); + } + } + + Field field = clz.getField("field"); + Annotation[] annotationsInField = field.getDeclaredAnnotations(); + for (Annotation annotation : annotationsInField){ + if (annotation instanceof MyAnnotation){ + MyAnnotation myAnnotation = (MyAnnotation)annotation; + System.out.println("name: " + myAnnotation.name()); + System.out.println("value:" + myAnnotation.value()); + } + } + + Method method1 = clz.getMethod("doOtherThing",String.class); + Annotation[][] annotationInParam = method1.getParameterAnnotations(); + Class[] params = method1.getParameterTypes(); + int i = 0; + for (Annotation[] annotations: annotationInParam){ + Class para = params[i++]; + for (Annotation annotation : annotations){ + if(annotation instanceof MyAnnotation){ + MyAnnotation myAnnotation = (MyAnnotation) annotation; + System.out.println("param: " + para.getName()); + System.out.println("name : " + myAnnotation.name()); + System.out.println("value :" + myAnnotation.value()); + } + + } + } + + } +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/reflectiontutorialtest/ExampleObjectTest.java b/src/test/java/cn/byhieg/reflectiontutorialtest/ExampleObjectTest.java new file mode 100644 index 0000000..0693a4d --- /dev/null +++ b/src/test/java/cn/byhieg/reflectiontutorialtest/ExampleObjectTest.java @@ -0,0 +1,106 @@ +package cn.byhieg.reflectiontutorialtest; + +import cn.byhieg.reflectiontutorial.ExampleObject; +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Created by shiqifeng on 2017/1/9. + * Mail byhieg@gmail.com + */ +public class ExampleObjectTest extends TestCase { + + public void testReflect()throws Exception{ + Class exampleObjectClass = Class.forName("cn.byhieg.reflectiontutorial.ExampleObject"); + //得到类的名字 + String fullClassName = exampleObjectClass.getName(); + String simpleClassName = exampleObjectClass.getSimpleName(); + + System.out.println(fullClassName); + System.out.println(simpleClassName); + + //输出类的public方法 + Method[] methods = exampleObjectClass.getMethods(); + for (Method method : methods){ + System.out.println("method = "+ method.getName()); + } + + Method method = exampleObjectClass.getMethod("setAge",int.class); + System.out.println(method.getName()); + for (Class clz : method.getParameterTypes()){ + System.out.println("方法的参数" + clz.getName()); + } + System.out.println(method.getReturnType().getName()); + + System.out.println(method.invoke(exampleObjectClass.newInstance(),1)); + + + + + + + //得到类的关键字 + int modifiers = exampleObjectClass.getMethods()[0].getModifiers(); + System.out.println(Modifier.isPublic(modifiers)); + System.out.println(Modifier.isPrivate(modifiers)); + + + //得到包信息 + Package aPackage = exampleObjectClass.getPackage(); + System.out.println(aPackage); + + //得到父类 + Class superClass = exampleObjectClass.getSuperclass(); + System.out.println(superClass.getSimpleName()); + System.out.println("父类是不是抽象类 " + Modifier.isAbstract(superClass.getModifiers())); + Field field2 = superClass.getDeclaredField("father"); + System.out.println(field2.getName()); + + //得到接口 + Class[] classes = superClass.getInterfaces(); + System.out.println("父类的接口" + classes[0]); + + //构造器 + Constructor[] constructors = exampleObjectClass.getConstructors(); + for (int i = 0;i < constructors.length;i++){ + Class[] parameterTypes = constructors[i].getParameterTypes(); + System.out.println("构造器参数如下========================"); + for (Class clz : parameterTypes){ + System.out.println("参数类型 " + clz.toString()); + } + } + //得到构造器的参数类型 + Constructor constructor = exampleObjectClass.getConstructor(int.class,Integer.class); + System.out.println(constructor.getParameterTypes()[0].toString()); + System.out.println(constructor.toString()); + + Constructor constructor1 = exampleObjectClass.getConstructor(String.class); + System.out.println(constructor1.newInstance("byhieg")); + + + //得到变量 + Field[] fields = exampleObjectClass.getFields(); + for (Field field : fields){ + System.out.println("变量为: " + field.getName()); + } + Field field1 = exampleObjectClass.getField("age"); + System.out.println("变量为:" + field1.toString()); + + ExampleObject object = ((ExampleObject) constructor1.newInstance("byhieg")); + System.out.println("原先的age是 " + object.age); + field1.set(object,10); + System.out.println("更改之后的age是" + object.age); + + //得到注解 + Annotation[] annotations = exampleObjectClass.getAnnotations(); + for (Annotation annotation : annotations){ + System.out.println(annotation.toString()); + } + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/reflectiontutorialtest/GenericObjectTest.java b/src/test/java/cn/byhieg/reflectiontutorialtest/GenericObjectTest.java new file mode 100644 index 0000000..0d44148 --- /dev/null +++ b/src/test/java/cn/byhieg/reflectiontutorialtest/GenericObjectTest.java @@ -0,0 +1,59 @@ +package cn.byhieg.reflectiontutorialtest; + +import cn.byhieg.reflectiontutorial.GenericObject; +import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; +import junit.framework.TestCase; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.List; + +/** + * Created by byhieg on 17/1/9. + * Mail to byhieg@gmail.com + */ +public class GenericObjectTest extends TestCase { + + public void testGeneric()throws Exception{ + Class clz = GenericObject.class; + Method getMethod = clz.getMethod("getLists"); + Type genericType = getMethod.getGenericReturnType(); + if(genericType instanceof ParameterizedType){ + ParameterizedType parameterizedType = ((ParameterizedType) genericType); + Type[] types = parameterizedType.getActualTypeArguments(); + for (Type type : types){ + Class actualClz = ((Class) type); + System.out.println("参数化类型为 : " + actualClz); + } + } + + Method setMethod = clz.getMethod("setLists", List.class); + Type[] genericParameterTypes = setMethod.getGenericParameterTypes(); + for (Type genericParameterType: genericParameterTypes){ + System.out.println("GenericParameterTypes为 : " + genericParameterType.getTypeName()); + if(genericParameterType instanceof ParameterizedType){ + ParameterizedType parameterizedType = ((ParameterizedType) genericParameterType); + System.out.println("ParameterizedType为 :" + parameterizedType.getTypeName()); + Type types[] = parameterizedType.getActualTypeArguments(); + for (Type type : types){ + System.out.println("参数化类型为 : " + ((Class) type).getName()); + } + } + + } + + Field field = clz.getField("lists"); + Type type = field.getGenericType(); + if (type instanceof ParameterizedType){ + ParameterizedType parameterizedType = ((ParameterizedType) type); + Type [] types = parameterizedType.getActualTypeArguments(); + for (Type type1 : types) { + System.out.println("参数化类型 : " + ((Class) type1).getTypeName()); + } + } + + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/reflectiontutorialtest/MyListTest.java b/src/test/java/cn/byhieg/reflectiontutorialtest/MyListTest.java new file mode 100644 index 0000000..8822047 --- /dev/null +++ b/src/test/java/cn/byhieg/reflectiontutorialtest/MyListTest.java @@ -0,0 +1,16 @@ +package cn.byhieg.reflectiontutorialtest; + +import cn.byhieg.reflectiontutorial.MyList; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/9. + * Mail to byhieg@gmail.com + */ +public class MyListTest extends TestCase { + + public void testGeneric() throws Exception{ + Class clz = MyList.class; + System.out.println(clz.getTypeParameters()[0]); + } +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/DeadLockTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/DeadLockTest.java new file mode 100644 index 0000000..daf4e64 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/DeadLockTest.java @@ -0,0 +1,27 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.DeadLock; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/1/4. + * Mail byhieg@gmail.com + */ +public class DeadLockTest extends TestCase { + public void testRun() throws Exception { + DeadLock deadLock = new DeadLock(); + deadLock.setFlag("a"); + + Thread threadA = new Thread(deadLock); + threadA.start(); + Thread.sleep(100); + + deadLock.setFlag("b"); + Thread threadB = new Thread(deadLock); + threadB.start(); + + Thread.sleep(1000 * 150); + + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/ExceptionServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/ExceptionServiceTest.java new file mode 100644 index 0000000..6b0f8f7 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/ExceptionServiceTest.java @@ -0,0 +1,27 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.ExceptionService; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/5. + * Mail to byhieg@gmail.com + */ +public class ExceptionServiceTest extends TestCase { + + + public void testGetFile() throws Exception{ + ExceptionService service = new ExceptionService(); + + new Thread(()->{ + service.getFile(); + }).start(); + Thread.sleep(100); + new Thread(()->{ + service.getFile(); + }).start(); + + Thread.sleep(1000 * 10); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/HalfTaskThreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/HalfTaskThreadTest.java new file mode 100644 index 0000000..e2a8ad3 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/HalfTaskThreadTest.java @@ -0,0 +1,25 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.HalfSynTask; +import cn.byhieg.threadtutorial.char02.HalfTaskThread; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class HalfTaskThreadTest extends TestCase { + public void testRun() throws Exception { + HalfSynTask task = new HalfSynTask(); + HalfTaskThread threadA = new HalfTaskThread(task); + threadA.setName("A"); + threadA.start(); + + HalfTaskThread threadB = new HalfTaskThread(task); + threadB.setName("B"); + threadB.start(); + + Thread.sleep(1000 * 10); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/HasSelfPrivateNumTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/HasSelfPrivateNumTest.java new file mode 100644 index 0000000..5fb3058 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/HasSelfPrivateNumTest.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.HasSelfPrivateNum; +import cn.byhieg.threadtutorial.char02.SelfPrivateThreadA; +import cn.byhieg.threadtutorial.char02.SelfPrivateThreadB; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/1. + * Mail to byhieg@gmail.com + */ +public class HasSelfPrivateNumTest extends TestCase { + public void testAddI() throws Exception { + HasSelfPrivateNum numA = new HasSelfPrivateNum(); + HasSelfPrivateNum numB = new HasSelfPrivateNum(); + SelfPrivateThreadA threadA = new SelfPrivateThreadA(numA); + threadA.start(); + SelfPrivateThreadB threadB = new SelfPrivateThreadB(numB); + threadB.start(); + Thread.sleep(1000 * 3); + } +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/InnerClass1Test.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/InnerClass1Test.java new file mode 100644 index 0000000..0d6333e --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/InnerClass1Test.java @@ -0,0 +1,36 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.OutClass; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/1/4. + * Mail byhieg@gmail.com + */ +public class InnerClass1Test extends TestCase { + public void testMethod() throws Exception { + final OutClass.InnerClass1 in1 = new OutClass.InnerClass1(); + final OutClass.InnerClass2 in2 = new OutClass.InnerClass2(); + + new Thread(new Runnable() { + public void run() { + in1.method1(in2); + } + },"T1").start(); + + new Thread(new Runnable() { + public void run() { + in1.method2(); + } + },"T2").start(); + + new Thread(new Runnable() { + public void run() { + in2.method1(); + } + },"T3").start(); + + Thread.sleep(1000 * 10); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/ListThreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/ListThreadTest.java new file mode 100644 index 0000000..e434d9c --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/ListThreadTest.java @@ -0,0 +1,27 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.ListThread; +import cn.byhieg.threadtutorial.char02.MyOneList; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class ListThreadTest extends TestCase { + public void testRun() throws Exception { + MyOneList list = new MyOneList(); + ListThread a = new ListThread(list,"A"); + a.setName("A"); + a.start(); + + ListThread b = new ListThread(list,"B"); + b.setName("B"); + b.start(); + + Thread.sleep(1000 * 6); + + System.out.println("listSize=" + list.getSize()); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/LongTimeServiceThreadATest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/LongTimeServiceThreadATest.java new file mode 100644 index 0000000..e031a57 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/LongTimeServiceThreadATest.java @@ -0,0 +1,43 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.CommonUtils; +import cn.byhieg.threadtutorial.char02.LongTimeServiceThreadA; +import cn.byhieg.threadtutorial.char02.LongTimeServiceThreadB; +import cn.byhieg.threadtutorial.char02.LongTimeTask; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class LongTimeServiceThreadATest extends TestCase { + + public void testRun() throws Exception { + LongTimeTask task = new LongTimeTask(); + LongTimeServiceThreadA threadA = new LongTimeServiceThreadA(task); + threadA.start(); + + LongTimeServiceThreadB threadB = new LongTimeServiceThreadB(task); + threadB.start(); + + try{ + Thread.sleep(1000 * 10); + }catch (InterruptedException e){ + e.printStackTrace(); + } + + long beginTime = CommonUtils.beginTime1; + if (CommonUtils.beginTime2 < CommonUtils.beginTime1){ + beginTime = CommonUtils.beginTime2; + } + + long endTime = CommonUtils.endTime1; + if (CommonUtils.endTime2 < CommonUtils.endTime1){ + endTime = CommonUtils.endTime2; + } + System.out.println("耗时:" + ((endTime - beginTime) / 1000)); + + Thread.sleep(1000 * 20); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/ObjectServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/ObjectServiceTest.java new file mode 100644 index 0000000..a88b306 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/ObjectServiceTest.java @@ -0,0 +1,28 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.DoubleSynThreadA; +import cn.byhieg.threadtutorial.char02.DoubleSynThreadB; +import cn.byhieg.threadtutorial.char02.ObjectService; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class ObjectServiceTest extends TestCase { + public void testServiceMethod() throws Exception { + ObjectService objectService = new ObjectService(); + DoubleSynThreadA a = new DoubleSynThreadA(objectService); + a.setName("A"); + a.start(); + + DoubleSynThreadB b = new DoubleSynThreadB(objectService); + b.setName("B"); + b.start(); + + Thread.sleep(1000 * 3); + } + + + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/PrintStringTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/PrintStringTest.java new file mode 100644 index 0000000..bf3f2f3 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/PrintStringTest.java @@ -0,0 +1,18 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.PrintString; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/1/4. + * Mail byhieg@gmail.com + */ +public class PrintStringTest extends TestCase { + public void testPrintStringMethod() throws Exception { + PrintString printStringService = new PrintString(); + new Thread(printStringService).start(); + System.out.println("我要停止他!stopThread=" + Thread.currentThread().getName()); + printStringService.setContinuePrint(false); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/PublicVarThreadATest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/PublicVarThreadATest.java new file mode 100644 index 0000000..b65a76a --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/PublicVarThreadATest.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.PublicVar; +import cn.byhieg.threadtutorial.char02.PublicVarThreadA; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/1. + * Mail to byhieg@gmail.com + */ +public class PublicVarThreadATest extends TestCase { + public void testRun() throws Exception { + PublicVar publicVarRef = new PublicVar(); + PublicVarThreadA threadA = new PublicVarThreadA(publicVarRef); + threadA.start(); + Thread.sleep(40); + publicVarRef.getValue(); + + Thread.sleep(1000 * 5); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/RunServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/RunServiceTest.java new file mode 100644 index 0000000..721cca8 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/RunServiceTest.java @@ -0,0 +1,25 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.RunService; +import cn.byhieg.threadtutorial.char02.SynVolaThreadA; +import cn.byhieg.threadtutorial.char02.SynVolaThreadB; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/5. + * Mail to byhieg@gmail.com + */ +public class RunServiceTest extends TestCase { + public void testRunMethod() throws Exception { + RunService service = new RunService(); + SynVolaThreadA threadA = new SynVolaThreadA(service); + threadA.start(); + Thread.sleep(1000); + SynVolaThreadB threadB = new SynVolaThreadB(service); + threadB.start(); + System.out.println("已经发起停止的命令了"); + + Thread.sleep(1000); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/RunThreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/RunThreadTest.java new file mode 100644 index 0000000..73a8354 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/RunThreadTest.java @@ -0,0 +1,21 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.RunThread; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/5. + * Mail to byhieg@gmail.com + */ +public class RunThreadTest extends TestCase { + public void testRun() throws Exception { + RunThread thread = new RunThread(); + thread.start(); + Thread.sleep(1000); + thread.setRunning(false); + System.out.println("已经赋值为false"); + + Thread.sleep(1000 * 3); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/SonSynTreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/SonSynTreadTest.java new file mode 100644 index 0000000..a486a78 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/SonSynTreadTest.java @@ -0,0 +1,17 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.SonSynTread; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class SonSynTreadTest extends TestCase { + public void testRun() throws Exception { + SonSynTread thread = new SonSynTread(); + thread.start(); + + Thread.sleep(1000 * 10); + } +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/StaticServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/StaticServiceTest.java new file mode 100644 index 0000000..c1eff6f --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/StaticServiceTest.java @@ -0,0 +1,24 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.StaticService; +import junit.framework.TestCase; + +import javax.management.relation.RoleUnresolved; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class StaticServiceTest extends TestCase { + + public void testPrint() throws Exception{ + new Thread(StaticService::printA).start(); + + new Thread(StaticService::printB).start(); + + new Thread(() -> new StaticService().printC()).start(); + + Thread.sleep(1000 * 3); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/SynBlockServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/SynBlockServiceTest.java new file mode 100644 index 0000000..4649ea9 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/SynBlockServiceTest.java @@ -0,0 +1,27 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.SynBlockService; +import cn.byhieg.threadtutorial.char02.SynBlockThreadA; +import cn.byhieg.threadtutorial.char02.SynBlockThreadB; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/3. + * Mail to byhieg@gmail.com + */ +public class SynBlockServiceTest extends TestCase { + public void testSetUSernamePassword() throws Exception { + SynBlockService service = new SynBlockService(); + SynBlockThreadA a = new SynBlockThreadA(service); + a.setName("A"); + a.start(); + + SynBlockThreadB b = new SynBlockThreadB(service); + b.setName("B"); + b.start(); + + Thread.sleep(1000 * 7); + + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/SynchronizedMethodThreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/SynchronizedMethodThreadTest.java new file mode 100644 index 0000000..b3ebb83 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/SynchronizedMethodThreadTest.java @@ -0,0 +1,25 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.MyObject; +import cn.byhieg.threadtutorial.char02.SynchronizedMethodThread; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/1. + * Mail to byhieg@gmail.com + */ +public class SynchronizedMethodThreadTest extends TestCase { + public void testRun() throws Exception { + MyObject object = new MyObject(); + SynchronizedMethodThread a = new SynchronizedMethodThread(object); + a.setName("A"); + SynchronizedMethodThread b = new SynchronizedMethodThread(object); + b.setName("B"); + + a.start(); + b.start(); + + Thread.sleep(1000 * 15); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/SynchronizedServiceThreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/SynchronizedServiceThreadTest.java new file mode 100644 index 0000000..eeec7ba --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/SynchronizedServiceThreadTest.java @@ -0,0 +1,18 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.SynchronizedServiceThread; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/1/3. + * Mail byhieg@gmail.com + */ +public class SynchronizedServiceThreadTest extends TestCase { + public void testRun() throws Exception { + SynchronizedServiceThread thread = new SynchronizedServiceThread(); + thread.start(); + + Thread.sleep(1000 * 3); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char02test/VolatileThreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char02test/VolatileThreadTest.java new file mode 100644 index 0000000..0e92bcf --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char02test/VolatileThreadTest.java @@ -0,0 +1,23 @@ +package cn.byhieg.threadtutorialtest.char02test; + +import cn.byhieg.threadtutorial.char02.VolatileThread; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/5. + * Mail to byhieg@gmail.com + */ +public class VolatileThreadTest extends TestCase { + public void testRun() throws Exception { + VolatileThread[] threads = new VolatileThread[100]; + for (int i = 0 ; i < 100; i++){ + threads[i] = new VolatileThread(); + } + for (int i = 0 ; i < 100 ; i++){ + threads[i].start(); + } + + Thread.sleep(1000 * 15); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char03test/AddSubTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char03test/AddSubTest.java new file mode 100644 index 0000000..c7531e5 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char03test/AddSubTest.java @@ -0,0 +1,38 @@ +package cn.byhieg.threadtutorialtest.char03test; + +import cn.byhieg.threadtutorial.char03.Add; +import cn.byhieg.threadtutorial.char03.AddThread; +import cn.byhieg.threadtutorial.char03.Subtract; +import cn.byhieg.threadtutorial.char03.SubtractThread; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class AddSubTest extends TestCase { + + public void testRun() throws Exception{ + Object lock = new Object(); + Add add = new Add(lock); + Subtract subtract1 = new Subtract(lock); + Subtract subtract2 = new Subtract(lock); + + AddThread addThread = new AddThread(add); + SubtractThread subtract1Thread = new SubtractThread(subtract1); + SubtractThread subtract2Thread = new SubtractThread(subtract2); + + subtract1Thread.setName("sub1Thread"); + subtract1Thread.start(); + + subtract2Thread.setName("sub2Thread"); + subtract2Thread.start(); + + Thread.sleep(1000 * 1); + addThread.setName("addThread"); + addThread.start(); + + Thread.sleep(5000); + + } +} diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char03test/CommonTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char03test/CommonTest.java new file mode 100644 index 0000000..d731b16 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char03test/CommonTest.java @@ -0,0 +1,40 @@ +package cn.byhieg.threadtutorialtest.char03test; + +import cn.byhieg.threadtutorial.char03.CommonNotify; +import cn.byhieg.threadtutorial.char03.CommonWait; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/15. + * Mail to byhieg@gmail.com + */ +public class CommonTest extends TestCase{ + + public void testRun() throws Exception{ + Object lock = new Object(); + new Thread(()->{ + try { + new CommonWait(lock).doSomething(); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + + new Thread(()->{ + try { + new CommonWait(lock).doSomething(); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + + Thread.sleep(1000); + + new Thread(()->{ + new CommonNotify(lock).doNotify(); + }).start(); + + Thread.sleep(1000 * 3); + + } +} diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char03test/JoinABCThreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char03test/JoinABCThreadTest.java new file mode 100644 index 0000000..95583eb --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char03test/JoinABCThreadTest.java @@ -0,0 +1,26 @@ +package cn.byhieg.threadtutorialtest.char03test; + +import cn.byhieg.threadtutorial.char03.JoinThreadA; +import cn.byhieg.threadtutorial.char03.JoinThreadB; +import cn.byhieg.threadtutorial.char03.JoinThreadC; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class JoinABCThreadTest extends TestCase { + + public void testRun() throws Exception{ + JoinThreadB b = new JoinThreadB(); + + JoinThreadA a = new JoinThreadA(b); + a.start(); + + Thread.sleep(1000); + JoinThreadC c = new JoinThreadC(b); + c.start(); + + Thread.sleep(1000 * 10); + } +} diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char03test/JoinThreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char03test/JoinThreadTest.java new file mode 100644 index 0000000..71116de --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char03test/JoinThreadTest.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorialtest.char03test; + +import cn.byhieg.threadtutorial.char03.JoinThread; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class JoinThreadTest extends TestCase { + public void testRun() throws Exception { + JoinThread joinThread = new JoinThread(); + joinThread.start(); + joinThread.join(); + System.out.println("我想当Join对象执行完毕后我再执行,我做到了"); + + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char03test/NotifyServiceThreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char03test/NotifyServiceThreadTest.java new file mode 100644 index 0000000..495726d --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char03test/NotifyServiceThreadTest.java @@ -0,0 +1,24 @@ +package cn.byhieg.threadtutorialtest.char03test; + +import cn.byhieg.threadtutorial.char03.NotifyServiceThread; +import cn.byhieg.threadtutorial.char03.Service; +import cn.byhieg.threadtutorial.char03.ServiceThread; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/1/10. + * Mail byhieg@gmail.com + */ +public class NotifyServiceThreadTest extends TestCase { + public void testRun() throws Exception { + Object lock = new Object(); + ServiceThread a = new ServiceThread(lock); + a.start(); + Thread.sleep(1000); + new NotifyServiceThread(lock).start(); + new NotifyServiceThread(lock).start(); + + Thread.sleep(1000 * 10); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char03test/ServiceThreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char03test/ServiceThreadTest.java new file mode 100644 index 0000000..29267ad --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char03test/ServiceThreadTest.java @@ -0,0 +1,26 @@ +package cn.byhieg.threadtutorialtest.char03test; + +import cn.byhieg.threadtutorial.char03.ServiceThread; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/1/10. + * Mail byhieg@gmail.com + */ +public class ServiceThreadTest extends TestCase { + + public void testRun() throws Exception { + Object lock = new Object(); + new ServiceThread(lock).start(); + new ServiceThread(lock).start(); + new Thread(new Runnable() { + @Override + public void run() { + System.out.println("aaa"); + } + }).start(); + + Thread.sleep(1000 * 4); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char03test/SynServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char03test/SynServiceTest.java new file mode 100644 index 0000000..c2af414 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char03test/SynServiceTest.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorialtest.char03test; + +import cn.byhieg.threadtutorial.char03.SynService; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/11. + * Mail to byhieg@gmail.com + */ +public class SynServiceTest extends TestCase { + + public void testDoSomething() throws Exception { + Object object = new Object(); + + new Thread(() -> new SynService(object).doSomething()).start(); + Thread.sleep(1000); + new Thread(() -> new SynService(object).doSomething()).start(); + + Thread.sleep(1000 * 15); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char03test/WaitThreadTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char03test/WaitThreadTest.java new file mode 100644 index 0000000..b92e6ed --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char03test/WaitThreadTest.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorialtest.char03test; + +import cn.byhieg.threadtutorial.char03.NotifyThread; +import cn.byhieg.threadtutorial.char03.WaitThread; +import junit.framework.TestCase; + +/** + * Created by shiqifeng on 2017/1/10. + * Mail byhieg@gmail.com + */ +public class WaitThreadTest extends TestCase { + + public void testWait()throws Exception{ + Object lock = new Object(); + new WaitThread(lock).start(); + Thread.sleep(50); + new NotifyThread(lock).start(); + + Thread.sleep(1000 * 15); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char04test/ConditionAllServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char04test/ConditionAllServiceTest.java new file mode 100644 index 0000000..19aff24 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char04test/ConditionAllServiceTest.java @@ -0,0 +1,29 @@ +package cn.byhieg.threadtutorialtest.char04test; + +import cn.byhieg.threadtutorial.char04.ConditionAllService; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/27. + * Mail to byhieg@gmail.com + */ +public class ConditionAllServiceTest extends TestCase { + public void testAwaitA() throws Exception { + ConditionAllService service = new ConditionAllService(); + Thread a = new Thread(service::awaitA); + a.setName("A"); + a.start(); + + Thread b = new Thread(service::awaitB); + b.setName("B"); + b.start(); + + Thread.sleep(1000 * 3); + + service.signAAll(); + + Thread.sleep(1000 * 4); + + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char04test/ConditionWaitNotifyServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char04test/ConditionWaitNotifyServiceTest.java new file mode 100644 index 0000000..a647b7a --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char04test/ConditionWaitNotifyServiceTest.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorialtest.char04test; + +import cn.byhieg.threadtutorial.char04.ConditionWaitNotifyService; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/27. + * Mail to byhieg@gmail.com + */ +public class ConditionWaitNotifyServiceTest extends TestCase { + public void testAwait() throws Exception { + ConditionWaitNotifyService service = new ConditionWaitNotifyService(); + new Thread(service::await).start(); + Thread.sleep(1000 * 3); + service.signal(); + Thread.sleep(1000); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char04test/FairServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char04test/FairServiceTest.java new file mode 100644 index 0000000..6710d82 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char04test/FairServiceTest.java @@ -0,0 +1,28 @@ +package cn.byhieg.threadtutorialtest.char04test; + +import cn.byhieg.threadtutorial.char04.FairService; +import junit.framework.TestCase; + +import javax.security.auth.callback.ConfirmationCallback; + +/** + * Created by byhieg on 17/1/27. + * Mail to byhieg@gmail.com + */ +public class FairServiceTest extends TestCase { + public void testServiceMethod() throws Exception { + + FairService fairService = new FairService(false); + Thread[] threadArrays = new Thread[10]; + for (int i = 0 ; i < threadArrays.length;i++){ + threadArrays[i] = new Thread(fairService::serviceMethod); + } + + for (Thread thread : threadArrays){ + thread.start(); + } + + Thread.sleep(1000 * 5); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char04test/HoldCountServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char04test/HoldCountServiceTest.java new file mode 100644 index 0000000..5944d50 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char04test/HoldCountServiceTest.java @@ -0,0 +1,19 @@ +package cn.byhieg.threadtutorialtest.char04test; + +import cn.byhieg.threadtutorial.char04.HoldCountService; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/27. + * Mail to byhieg@gmail.com + */ +public class HoldCountServiceTest extends TestCase { + public void testServiceMethod1() throws Exception { + + HoldCountService service = new HoldCountService(); + service.serviceMethod1(); + + Thread.sleep(1000 * 5); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char04test/MyConditionMoreServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char04test/MyConditionMoreServiceTest.java new file mode 100644 index 0000000..bef0df4 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char04test/MyConditionMoreServiceTest.java @@ -0,0 +1,36 @@ +package cn.byhieg.threadtutorialtest.char04test; + +import cn.byhieg.threadtutorial.char04.MyConditionMoreService; +import cn.byhieg.threadtutorial.char04.ThreadA; +import cn.byhieg.threadtutorial.char04.ThreadB; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/26. + * Mail to byhieg@gmail.com + */ +public class MyConditionMoreServiceTest extends TestCase { + + + public void testMethod() throws Exception { + MyConditionMoreService service = new MyConditionMoreService(); + ThreadA a = new ThreadA(service); + a.setName("A"); + a.start(); + + ThreadA aa = new ThreadA(service); + aa.setName("AA"); + aa.start(); + + ThreadB b = new ThreadB(service); + b.setName("B"); + b.start(); + + ThreadB bb = new ThreadB(service); + bb.setName("BB"); + bb.start(); + + Thread.sleep(1000 * 30); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char04test/MyConditionServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char04test/MyConditionServiceTest.java new file mode 100644 index 0000000..f643082 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char04test/MyConditionServiceTest.java @@ -0,0 +1,29 @@ +package cn.byhieg.threadtutorialtest.char04test; + +import cn.byhieg.threadtutorial.char04.MyConditionService; +import junit.framework.TestCase; + +import java.util.Locale; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Created by byhieg on 17/1/26. + * Mail to byhieg@gmail.com + */ +public class MyConditionServiceTest extends TestCase { + + public void testTestMethod() throws Exception { + MyConditionService service = new MyConditionService(); + new Thread(service::testMethod).start(); + new Thread(service::testMethod).start(); + new Thread(service::testMethod).start(); + new Thread(service::testMethod).start(); + new Thread(service::testMethod).start(); + + Lock lock = new ReentrantLock(true); + lock.lockInterruptibly(); + Thread.sleep(1000 * 5); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char04test/ReadReadServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char04test/ReadReadServiceTest.java new file mode 100644 index 0000000..d7d1c92 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char04test/ReadReadServiceTest.java @@ -0,0 +1,24 @@ +package cn.byhieg.threadtutorialtest.char04test; + +import cn.byhieg.threadtutorial.char04.ReadReadService; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/28. + * Mail to byhieg@gmail.com + */ +public class ReadReadServiceTest extends TestCase { + public void testRead() throws Exception { + ReadReadService service = new ReadReadService(); + Thread a = new Thread(service::read); + a.setName("A"); + + Thread b = new Thread(service::read); + b.setName("B"); + + a.start(); + b.start(); + + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char04test/ReadWriteServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char04test/ReadWriteServiceTest.java new file mode 100644 index 0000000..1e62ef3 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char04test/ReadWriteServiceTest.java @@ -0,0 +1,27 @@ +package cn.byhieg.threadtutorialtest.char04test; + +import cn.byhieg.threadtutorial.char04.ReadWriteService; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/28. + * Mail to byhieg@gmail.com + */ +public class ReadWriteServiceTest extends TestCase { + public void testRead() throws Exception { + + ReadWriteService service = new ReadWriteService(); + Thread a = new Thread(service::read); + a.setName("AA"); + a.start(); + Thread.sleep(1000); + + Thread b = new Thread(service::write); + b.setName("BB"); + + + b.start(); + Thread.sleep(1000 * 30); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char04test/WriteReadServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char04test/WriteReadServiceTest.java new file mode 100644 index 0000000..0f6ac07 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char04test/WriteReadServiceTest.java @@ -0,0 +1,27 @@ +package cn.byhieg.threadtutorialtest.char04test; + +import cn.byhieg.threadtutorial.char04.WriteReadService; +import cn.byhieg.threadtutorial.char04.WriteWriteService; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/28. + * Mail to byhieg@gmail.com + */ +public class WriteReadServiceTest extends TestCase { + public void testWrite() throws Exception { + + WriteReadService service = new WriteReadService(); + Thread a = new Thread(service::write); + a.setName("A"); + a.start(); + Thread.sleep(1000); + + Thread b = new Thread(service::read); + b.setName("B"); + b.start(); + + Thread.sleep(1000 * 30); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char04test/WriteWriteServiceTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char04test/WriteWriteServiceTest.java new file mode 100644 index 0000000..9efd971 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char04test/WriteWriteServiceTest.java @@ -0,0 +1,23 @@ +package cn.byhieg.threadtutorialtest.char04test; + +import cn.byhieg.threadtutorial.char04.WriteWriteService; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/1/28. + * Mail to byhieg@gmail.com + */ +public class WriteWriteServiceTest extends TestCase { + public void testWrite() throws Exception { + WriteWriteService service = new WriteWriteService(); + Thread a = new Thread(service::write); + a.setName("A"); + Thread b = new Thread(service::write); + b.setName("B"); + + a.start(); + b.start(); + Thread.sleep(1000 * 30); + } + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char05test/More2moreListTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char05test/More2moreListTest.java new file mode 100644 index 0000000..f07c8d5 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char05test/More2moreListTest.java @@ -0,0 +1,33 @@ +package cn.byhieg.threadtutorialtest.char05test; + +import cn.byhieg.threadtutorial.char05.more2more.list.Customer; +import cn.byhieg.threadtutorial.char05.more2more.list.MyQueue; +import cn.byhieg.threadtutorial.char05.more2more.list.Producer; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class More2moreListTest extends TestCase { + + public void testList() throws Exception{ + MyQueue queue = new MyQueue(); + new Thread(new Producer(queue)).start(); + new Thread(new Producer(queue)).start(); + new Thread(new Producer(queue)).start(); + new Thread(new Producer(queue)).start(); + new Thread(new Producer(queue)).start(); + + + new Thread(new Customer(queue)).start(); + new Thread(new Customer(queue)).start(); + new Thread(new Customer(queue)).start(); + new Thread(new Customer(queue)).start(); + new Thread(new Customer(queue)).start(); + + + Thread.sleep(1000 * 5); + } + +} diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char05test/More2moreValueTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char05test/More2moreValueTest.java new file mode 100644 index 0000000..dc91193 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char05test/More2moreValueTest.java @@ -0,0 +1,64 @@ +package cn.byhieg.threadtutorialtest.char05test; + +import cn.byhieg.threadtutorial.char04.ThreadA; + +import cn.byhieg.threadtutorial.char05.more2more.value.Customer; +import cn.byhieg.threadtutorial.char05.more2more.value.Producer; +import junit.framework.TestCase; +import sun.nio.cs.ext.MacThai; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class More2moreValueTest extends TestCase{ + public void testValue() throws Exception { + String lock = "lock"; + + Producer producer = new Producer(lock); + Customer customer = new Customer(lock); + + Thread [] pThread = new Thread[2]; + Thread [] cThread = new Thread[2]; + + for (int i = 0 ; i < 2;i++){ + pThread[i] = new Thread(()->{ + try { + for (int j = 0 ; j < 4;j++) { + producer.setValue(); + } + + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + pThread[i].setName("生产者" + (i + 1)); + pThread[i].start(); + + cThread[i] = new Thread(()->{ + try { + for (int j = 0 ; j< 4 ;j++){ + customer.getValue(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + + cThread[i].setName("消费者" + (i + 1)); + cThread[i].start(); + } + + Thread.sleep(1000); + Thread[] threadArray = new Thread[Thread.currentThread().getThreadGroup().activeCount()]; + Thread.currentThread().getThreadGroup().enumerate(threadArray); + for (Thread aThreadArray : threadArray) { + System.out.println(aThreadArray.getName() + " " + aThreadArray.getState()); + } + + + + } + + +} diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char05test/More2oneListTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char05test/More2oneListTest.java new file mode 100644 index 0000000..f55e3c3 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char05test/More2oneListTest.java @@ -0,0 +1,28 @@ +package cn.byhieg.threadtutorialtest.char05test; + + +import cn.byhieg.threadtutorial.char05.more2one.Customer; +import cn.byhieg.threadtutorial.char05.more2one.MyQueue; +import cn.byhieg.threadtutorial.char05.more2one.Producer; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class More2oneListTest extends TestCase { + + public void testList() throws Exception{ + MyQueue queue = new MyQueue(); + + new Thread(new Producer(queue)).start(); + new Thread(new Producer(queue)).start(); + new Thread(new Producer(queue)).start(); + new Thread(new Producer(queue)).start(); + new Thread(new Producer(queue)).start(); + + new Thread(new Customer(queue)).start(); + + Thread.sleep(1000 * 3); + } +} diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char05test/One2moreListTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char05test/One2moreListTest.java new file mode 100644 index 0000000..f6dee8d --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char05test/One2moreListTest.java @@ -0,0 +1,29 @@ +package cn.byhieg.threadtutorialtest.char05test; + +import cn.byhieg.threadtutorial.char05.one2more.Customer; +import cn.byhieg.threadtutorial.char05.one2more.MyQueue; +import cn.byhieg.threadtutorial.char05.one2more.Producer; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class One2moreListTest extends TestCase { + + public void testList() throws Exception { + MyQueue queue = new MyQueue(); + + new Thread(new Producer(queue)).start(); + new Thread(new Customer(queue)).start(); + + new Thread(new Customer(queue)).start(); + new Thread(new Customer(queue)).start(); + new Thread(new Customer(queue)).start(); + new Thread(new Customer(queue)).start(); + + Thread.sleep(1000 * 3); + + + } +} diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char05test/One2oneListTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char05test/One2oneListTest.java new file mode 100644 index 0000000..78dd5ca --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char05test/One2oneListTest.java @@ -0,0 +1,22 @@ +package cn.byhieg.threadtutorialtest.char05test; + +import cn.byhieg.threadtutorial.char05.one2one.list.Customer; +import cn.byhieg.threadtutorial.char05.one2one.list.MyQueue; +import cn.byhieg.threadtutorial.char05.one2one.list.Producer; +import junit.framework.TestCase; +import org.omg.PortableServer.THREAD_POLICY_ID; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class One2oneListTest extends TestCase{ + + public void testList() throws Exception { + MyQueue queue = new MyQueue(); + + new Thread(new Customer(queue)).start(); + new Thread(new Producer(queue)).start(); + + } +} diff --git a/src/test/java/cn/byhieg/threadtutorialtest/char05test/One2oneValueTest.java b/src/test/java/cn/byhieg/threadtutorialtest/char05test/One2oneValueTest.java new file mode 100644 index 0000000..9dd4fe0 --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/char05test/One2oneValueTest.java @@ -0,0 +1,43 @@ +package cn.byhieg.threadtutorialtest.char05test; + +import cn.byhieg.threadtutorial.char05.one2one.value.Customer; +import cn.byhieg.threadtutorial.char05.one2one.value.Producer; +import junit.framework.TestCase; + +/** + * Created by byhieg on 17/2/1. + * Mail to byhieg@gmail.com + */ +public class One2oneValueTest extends TestCase { + + public void testValue() throws Exception{ + String lock = "lock"; + Producer producer = new Producer(lock); + Customer customer = new Customer(lock); + + new Thread(() -> { + try { + for (;;) { + producer.setValue(); + } + + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); + + + new Thread(()->{ + try { + for (;;) { + customer.getValue(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); + + Thread.sleep(1000 * 5); + } + +} diff --git a/src/test/java/cn/byhieg/threadtutorialtest/concurrenttest/atomtest/AtomFactoryTest.java b/src/test/java/cn/byhieg/threadtutorialtest/concurrenttest/atomtest/AtomFactoryTest.java new file mode 100644 index 0000000..e8b706a --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/concurrenttest/atomtest/AtomFactoryTest.java @@ -0,0 +1,82 @@ +package cn.byhieg.threadtutorialtest.concurrenttest.atomtest; + +import cn.byhieg.threadtutorial.concurrent.atom.AtomFactory; + +import cn.byhieg.threadtutorial.concurrent.atom.MyObject; +import junit.framework.TestCase; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicIntegerArray; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Created by shiqifeng on 2017/5/5. + * Mail byhieg@gmail.com + */ +public class AtomFactoryTest extends TestCase { + AtomicInteger integer; + AtomicIntegerArray array; + AtomicReference reference; + AtomicIntegerFieldUpdater updater; + + public void setUp() throws Exception { + super.setUp(); + integer = AtomFactory.getInstance().createAtomInt(1); + } + + public void testAtomInt() throws Exception { + System.out.println("int原子类"); + new Thread(()->{ + for (int i = 0; i < 10; i++) { + integer.getAndIncrement(); + System.out.println(getName() + " " + integer.get()); + } + }).start(); + + new Thread(()->{ + for (int i = 0; i < 10; i++) { + integer.getAndIncrement(); + System.out.println(getName() + " " + integer.get()); + } + }).start(); + + Thread.sleep(1000); + } + + public void testAtomArray() throws Exception { + System.out.println("原子类数组"); + int [] value = new int[]{1,2,3,4}; + array = AtomFactory.getInstance().createAtomArray(value); + array.getAndSet(1,10); + System.out.println(array.get(1)); + System.out.println(value[1]); + } + + public void testAtomRef()throws Exception { + System.out.println("原子类"); + MyObject object = new MyObject(); + reference = AtomFactory.getInstance().createAtomReference(object); + reference.set(object); + MyObject newObject = new MyObject(); + newObject.name = "xiaoli"; + reference.compareAndSet(object, newObject); + System.out.println(reference.get().name); + } + + + public void testUpdater() throws Exception { + System.out.println("原子类更新字段"); + updater = AtomFactory.getInstance().createAtomIntegerUpdate("id"); + MyObject object = new MyObject(); + System.out.println(updater.getAndIncrement(object)); + System.out.println(updater.get(object)); + } + + + public void tearDown() throws Exception { + + } + + +} \ No newline at end of file diff --git a/src/test/java/cn/byhieg/threadtutorialtest/concurrenttest/blockingtest/ArrayBlockTest.java b/src/test/java/cn/byhieg/threadtutorialtest/concurrenttest/blockingtest/ArrayBlockTest.java new file mode 100644 index 0000000..c48566c --- /dev/null +++ b/src/test/java/cn/byhieg/threadtutorialtest/concurrenttest/blockingtest/ArrayBlockTest.java @@ -0,0 +1,34 @@ +package cn.byhieg.threadtutorialtest.concurrenttest.blockingtest; + +import cn.byhieg.threadtutorial.concurrent.blocking.ArrayBlock; +import cn.byhieg.threadtutorial.concurrent.blocking.Costumer; +import cn.byhieg.threadtutorial.concurrent.blocking.Producer; +import junit.framework.TestCase; + +import javax.swing.*; + +/** + * Created by byhieg on 17/5/3. + * Mail to byhieg@gmail.com + */ +public class ArrayBlockTest extends TestCase { + ArrayBlock block; + public void setUp() throws Exception { + super.setUp(); + block = new ArrayBlock(2); + } + + public void tearDown() throws Exception { + } + + + public void testBlocking() throws Exception { + Producer producer = new Producer(block); + Costumer costumer = new Costumer(block); + producer.start(); + costumer.start(); + producer.join(); + costumer.join(); + + } +} \ No newline at end of file