├── APUE
├── chapter-3
│ ├── 3-7.jpg
│ ├── 3-8.png
│ ├── 3-9.jpg
│ ├── readme.md
│ ├── file_shared.md
│ └── basic_file_io.md
├── chapter-4
│ ├── readme.md
│ └── file_property.md
└── readme.md
├── Java多线程编程核心技术
├── threadlocal
│ ├── .readme.md.swp
│ ├── readme.md
│ ├── ThreadLocalExt.java
│ ├── Test.java
│ ├── Run.java
│ ├── DateVariableIsolation.java
│ └── VariableIsolation.java
├── add
│ ├── readme.md
│ └── StateMain.java
├── lock
│ ├── 20170517.md
│ ├── FairReentrantLock.java
│ ├── TryLockReentrantLock.java
│ ├── WriteWriteLock.java
│ ├── InterruptReentrantLock1.java
│ ├── ReadReentrantReadWriteLock.java
│ ├── InterruptReentrantLock.java
│ ├── ReadWriteLock.java
│ └── 20170508.md
├── thread
│ ├── src
│ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── sprint
│ │ │ │ ├── ch01
│ │ │ │ ├── ThreadMethods.java
│ │ │ │ ├── MyThread.java
│ │ │ │ ├── MyRunnable.java
│ │ │ │ ├── StopThread.java
│ │ │ │ ├── SleepThread.java
│ │ │ │ ├── ExceptionThread.java
│ │ │ │ └── ReturnThread.java
│ │ │ │ └── ch02
│ │ │ │ ├── method
│ │ │ │ ├── Syn.java
│ │ │ │ ├── SynThreadA.java
│ │ │ │ ├── SynThreadB.java
│ │ │ │ ├── UnSafeInitVarThreadA.java
│ │ │ │ ├── UnSafeInitVarThreadB.java
│ │ │ │ ├── MoreObjMoreLockThreadA.java
│ │ │ │ ├── SafeLocalVarThreadA.java
│ │ │ │ ├── SafeLocalVarThreadB.java
│ │ │ │ ├── MoreObjMoreLockThreadB.java
│ │ │ │ ├── SafeLocalVar.java
│ │ │ │ ├── UnSafeInitVar.java
│ │ │ │ └── MoreObjMoreLock.java
│ │ │ │ ├── block
│ │ │ │ ├── SynBlockThreadA.java
│ │ │ │ ├── SynBlockThreadB.java
│ │ │ │ └── SynBlock.java
│ │ │ │ └── volatiles
│ │ │ │ └── Volatile.java
│ │ └── test
│ │ │ └── java
│ │ │ └── com
│ │ │ └── sprint
│ │ │ ├── ch01
│ │ │ ├── MyThreadTest.java
│ │ │ ├── MyRunnableTest.java
│ │ │ ├── SleepThreadTest.java
│ │ │ ├── StopThreadTest.java
│ │ │ ├── ReturnThreadTest.java
│ │ │ ├── ExceptionThreadTest.java
│ │ │ └── ThreadMethodsTest.java
│ │ │ └── ch02
│ │ │ ├── method
│ │ │ ├── SynTest.java
│ │ │ ├── SafeLocalVarTest.java
│ │ │ ├── UnSafeInitVarTest.java
│ │ │ └── MoreObjMoreLockTest.java
│ │ │ ├── volatiles
│ │ │ └── VolatileTest.java
│ │ │ └── block
│ │ │ └── SynBlockTest.java
│ ├── build.gradle
│ └── readme.md
├── singleton
│ ├── readme.md
│ ├── StaticCode.java
│ ├── HungryModel.java
│ ├── InnerClass.java
│ ├── LazyModel.java
│ └── EnumSingleton.java
├── SimpleWN.java
├── readme.md
└── 等待通知机制.md
└── README.md
/APUE/chapter-3/3-7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaohuxing/books-learning/HEAD/APUE/chapter-3/3-7.jpg
--------------------------------------------------------------------------------
/APUE/chapter-3/3-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaohuxing/books-learning/HEAD/APUE/chapter-3/3-8.png
--------------------------------------------------------------------------------
/APUE/chapter-3/3-9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaohuxing/books-learning/HEAD/APUE/chapter-3/3-9.jpg
--------------------------------------------------------------------------------
/APUE/chapter-4/readme.md:
--------------------------------------------------------------------------------
1 | ## 文件和目录
2 |
3 | 上一章基本围绕着普通文件 I/O 进行打开,读和写的。这一章主要介绍`文件属性`和`文件系统`, 故将该章节分为两部分来学习:
4 |
5 | - [文件属性]
6 | - [文件系统]
7 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/threadlocal/.readme.md.swp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaohuxing/books-learning/HEAD/Java多线程编程核心技术/threadlocal/.readme.md.swp
--------------------------------------------------------------------------------
/Java多线程编程核心技术/add/readme.md:
--------------------------------------------------------------------------------
1 | ## 线程状态
2 | - timed_waiting 代表线程执行了Thread.sleep()方法
3 | - blocked 等待锁
4 | - waiting 线程执行Object.wait()
5 |
6 | 感觉主要引出线程池的概念
7 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/lock/20170517.md:
--------------------------------------------------------------------------------
1 | ## Lock
2 | - ReentrantLock
3 | - ReentrantReadWriteLock
4 |
5 | lock 做为的synchronized 替代方案,更加灵活.
6 | 大多数使用语义化的命名方式,具体使用详情见内部代码实现
7 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch01/ThreadMethods.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | public class ThreadMethods {
4 | //详情见ThreadMethodsTest.java
5 | }
6 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | repositories {
4 | mavenCentral()
5 | }
6 |
7 | dependencies {
8 | compile("junit:junit:4.12")
9 | }
10 |
--------------------------------------------------------------------------------
/APUE/readme.md:
--------------------------------------------------------------------------------
1 | ## UNIX 环境高级编程 (APUE) 学习笔记
2 |
3 | - [chapter-3 文件 I/O](./chapter-3/readme.md)
4 | - [基础的文件操作](./chapter-3/basic_file_io.md)
5 | - [文件共享](./chapter-3/file_shared.md)
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # books-learning
2 |
3 | #### 计算机基础
4 | - [UNIX 环境高级编程](./APUE/readme.md)
5 |
6 | #### Java
7 |
8 | - [Java 多线程编程核心技术](./Java多线程编程核心技术/readme.md)
9 |
10 |
11 |
--------------------------------------------------------------------------------
/APUE/chapter-3/readme.md:
--------------------------------------------------------------------------------
1 | ## 文件 I/O
2 |
3 | 大体了浏览了这一章,像我这样的初学者,可以将该章节分为两部分来学习:
4 |
5 | - [基础的文件操作:open, read, write, lseek, close](./basic_file_io.md)
6 | - [文件共享](./file_shared.md)
7 |
8 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/threadlocal/readme.md:
--------------------------------------------------------------------------------
1 | 类ThreadLocal的作用:主要解决每个线程绑定自己的值,用于共享变量的在多线程中的分离。
2 | - VariableIsolation, DateVariableIsolation.java 体现出ThreadLocal的作用
3 | - ThreadLocalExt.java 继承ThreadLocal,可以设置初始值
4 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/threadlocal/ThreadLocalExt.java:
--------------------------------------------------------------------------------
1 | public class ThreadLocalExt extends ThreadLocal {
2 |
3 | //重写了该方法后不存在null值
4 | @Override
5 | protected Object initValue() {
6 | return new Date().getTime();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch01/MyThread.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | public class MyThread extends Thread {
4 | @Override
5 | public void run() {
6 | System.out.println("进军Java 多线程");
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/threadlocal/Test.java:
--------------------------------------------------------------------------------
1 | public class Test {
2 | public static void main(String[] args) {
3 | System.out.println("hello go ");
4 | }
5 | }
6 |
7 | class Demo {
8 |
9 | }
10 |
11 | class Teacher {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/singleton/readme.md:
--------------------------------------------------------------------------------
1 | ## 单例模式与多线程(170518)
2 |
3 | - 立即加载/"饿汉模式" : HungryModel.java
4 | - 延迟加载/"懒汉模式" : LazyModel.java
5 | - 使用静态内置实现单例模式 : InnerClass.java
6 | - 使用static代码块实现单例模式 : StaticCode.java
7 | - 使用enum枚举实现单例 : EnumSingleton.java
8 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch01/MyRunnable.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | public class MyRunnable implements Runnable {
4 |
5 | @Override
6 | public void run() {
7 | System.out.println("多线程之Runnable实现");
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch01/MyThreadTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | import org.junit.Test;
4 | public class MyThreadTest {
5 |
6 | @Test
7 | public void testRun() {
8 | MyThread thread = new MyThread();
9 | thread.start();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch01/MyRunnableTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | import org.junit.Test;
4 | public class MyRunnableTest {
5 |
6 | @Test
7 | public void testRun() {
8 | Thread thread = new Thread(new MyRunnable());
9 | thread.start();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/Syn.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | public class Syn {
4 | public synchronized void method1() {
5 | System.out.println("method1");
6 | }
7 |
8 | public synchronized void method2() {
9 | System.out.println("method2");
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/SynThreadA.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | public class SynThreadA extends Thread {
4 | Syn syn;
5 | public SynThreadA(Syn syn) {
6 | this.syn = syn;
7 | }
8 |
9 | @Override
10 | public void run() {
11 | syn.method1();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/SynThreadB.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | public class SynThreadB extends Thread {
4 | Syn syn;
5 | public SynThreadB(Syn syn) {
6 | this.syn = syn;
7 | }
8 |
9 | @Override
10 | public void run() {
11 | syn.method2();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/threadlocal/Run.java:
--------------------------------------------------------------------------------
1 | public class Run {
2 | public static ThreadLocal t1 = new ThreadLocal();
3 | public static void main(String[] args) {
4 | if (t1.get() == null) {
5 | t1.set("我不是空值");
6 | }
7 | System.out.println(t1.get());
8 | System.out.println("获取数据,不像栈那样弹出来" + t1.get());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/block/SynBlockThreadA.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.block;
2 |
3 | public class SynBlockThreadA extends Thread {
4 | private SynBlock obj;
5 |
6 | public SynBlockThreadA(SynBlock obj) {
7 | this.obj = obj;
8 | }
9 |
10 | @Override
11 | public void run() {
12 | obj.doLongTimeTask();
13 | }
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/block/SynBlockThreadB.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.block;
2 |
3 | public class SynBlockThreadB extends Thread {
4 | private SynBlock obj;
5 |
6 | public SynBlockThreadB(SynBlock obj) {
7 | this.obj = obj;
8 | }
9 |
10 | @Override
11 | public void run() {
12 | obj.doLongTimeTask();
13 | }
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/UnSafeInitVarThreadA.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | public class UnSafeInitVarThreadA extends Thread {
4 | private UnSafeInitVar var;
5 | public UnSafeInitVarThreadA(UnSafeInitVar var) {
6 | this.var = var;
7 | }
8 |
9 | @Override
10 | public void run() {
11 | var.add("a");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/UnSafeInitVarThreadB.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | public class UnSafeInitVarThreadB extends Thread {
4 | private UnSafeInitVar var;
5 | public UnSafeInitVarThreadB(UnSafeInitVar var) {
6 | this.var = var;
7 | }
8 |
9 | @Override
10 | public void run() {
11 | var.add("b");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch01/SleepThreadTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | import org.junit.Test;
4 | public class SleepThreadTest {
5 |
6 | @Test
7 | public void testRun() throws InterruptedException {
8 | SleepThread thread = new SleepThread();
9 | thread.start();
10 | Thread.sleep(200);
11 | thread.interrupt();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch02/method/SynTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | import org.junit.Test;
4 | public class SynTest {
5 |
6 | @Test
7 | public void testRun() {
8 | Syn syn = new Syn();
9 | SynThreadA a = new SynThreadA(syn);
10 | a.start();
11 | SynThreadB b = new SynThreadB(syn);
12 | b.start();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/MoreObjMoreLockThreadA.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | public class MoreObjMoreLockThreadA extends Thread {
4 | private MoreObjMoreLock obj;
5 |
6 | public MoreObjMoreLockThreadA(MoreObjMoreLock obj) {
7 | this.obj = obj;
8 | }
9 |
10 | @Override
11 | public void run() {
12 | obj.add("a");
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch01/StopThreadTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | import org.junit.Test;
4 | public class StopThreadTest {
5 | //因耗时常,不利于其他测试,先注释掉
6 | // @Test
7 | public void testRun() throws InterruptedException {
8 | StopThread thread = new StopThread();
9 | thread.start();
10 | Thread.sleep(8000);
11 | thread.stop();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/SafeLocalVarThreadA.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | public class SafeLocalVarThreadA extends Thread {
4 | private SafeLocalVar localVar;
5 |
6 | public SafeLocalVarThreadA(SafeLocalVar localVar) {
7 | this.localVar = localVar;
8 | }
9 |
10 | @Override
11 | public void run() {
12 | localVar.add("a");
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/SafeLocalVarThreadB.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | public class SafeLocalVarThreadB extends Thread {
4 | private SafeLocalVar localVar;
5 |
6 | public SafeLocalVarThreadB(SafeLocalVar localVar) {
7 | this.localVar = localVar;
8 | }
9 |
10 | @Override
11 | public void run() {
12 | localVar.add("b");
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch01/ReturnThreadTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | import org.junit.Test;
4 | public class ReturnThreadTest {
5 |
6 | //因耗时常,不利于其他测试,先注释掉
7 | // @Test
8 | public void testRun() throws InterruptedException {
9 | ReturnThread thread = new ReturnThread();
10 | thread.start();
11 | Thread.sleep(2000);
12 | thread.interrupt();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/MoreObjMoreLockThreadB.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | //哇 文件名有点长了
4 | public class MoreObjMoreLockThreadB extends Thread {
5 | private MoreObjMoreLock obj;
6 |
7 | public MoreObjMoreLockThreadB(MoreObjMoreLock obj) {
8 | this.obj = obj;
9 | }
10 |
11 | @Override
12 | public void run() {
13 | obj.add("b");
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch01/ExceptionThreadTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | import org.junit.Test;
4 | public class ExceptionThreadTest {
5 |
6 | //因耗时常,不利于其他测试,先注释掉
7 | // @Test
8 | public void testRun() throws InterruptedException {
9 | ExceptionThread thread = new ExceptionThread();
10 | thread.start();
11 | Thread.sleep(2000);
12 | thread.interrupt();
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch02/volatiles/VolatileTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.volatiles;
2 |
3 | import org.junit.Test;
4 | public class VolatileTest {
5 |
6 | @Test
7 | public void testRun() throws InterruptedException {
8 | Volatile v = new Volatile();
9 | Thread thread = new Thread(v);
10 | thread.start();
11 | Thread.sleep(1000);
12 | v.setRunning(false);
13 |
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch01/StopThread.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | public class StopThread extends Thread{
4 | private int i = 0;
5 |
6 | @Override
7 | public void run() {
8 | try {
9 | while (true) {
10 | i++;
11 | System.out.println("i=" + i);
12 | Thread.sleep(1000);
13 | }
14 | } catch (InterruptedException e) {
15 | e.printStackTrace();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch02/method/SafeLocalVarTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | import org.junit.Test;
4 | public class SafeLocalVarTest {
5 |
6 | @Test
7 | public void testRun() {
8 | SafeLocalVar var = new SafeLocalVar();
9 | SafeLocalVarThreadA a = new SafeLocalVarThreadA(var);
10 | a.start();
11 | SafeLocalVarThreadB b = new SafeLocalVarThreadB(var);
12 | b.start();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch02/method/UnSafeInitVarTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | import org.junit.Test;
4 | public class UnSafeInitVarTest {
5 |
6 | @Test
7 | public void testRun() {
8 | UnSafeInitVar var = new UnSafeInitVar();
9 | UnSafeInitVarThreadA a = new UnSafeInitVarThreadA(var);
10 | a.start();
11 | UnSafeInitVarThreadB b = new UnSafeInitVarThreadB(var);
12 | b.start();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch02/block/SynBlockTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.block;
2 | import java.util.concurrent.CountDownLatch;
3 | import org.junit.Test;
4 | public class SynBlockTest {
5 |
6 | @Test
7 | public void testRun() {
8 | SynBlock obj = new SynBlock();
9 | SynBlockThreadA a = new SynBlockThreadA(obj);
10 | a.start();
11 | SynBlockThreadB b = new SynBlockThreadB(obj);
12 | b.start();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch01/SleepThread.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | public class SleepThread extends Thread {
4 |
5 | @Override
6 | public void run() {
7 | try {
8 | System.out.println("run start");
9 | Thread.sleep(200000);
10 | System.out.println("run end");
11 | } catch (InterruptedException e) {
12 | System.out.println("在沉睡中被停止!进入catch!" + this.isInterrupted());
13 | e.printStackTrace();
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch02/method/MoreObjMoreLockTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | import org.junit.Test;
4 | public class MoreObjMoreLockTest {
5 |
6 | @Test
7 | public void testRun() {
8 | MoreObjMoreLock obj = new MoreObjMoreLock();
9 | MoreObjMoreLockThreadA a = new MoreObjMoreLockThreadA(obj);
10 | a.start();
11 | MoreObjMoreLock obj1 = new MoreObjMoreLock();
12 | MoreObjMoreLockThreadB b = new MoreObjMoreLockThreadB(obj1);
13 | b.start();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/volatiles/Volatile.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.volatiles;
2 |
3 | public class Volatile implements Runnable {
4 | volatile private boolean isRunning = true;
5 | public boolean isRunning() {
6 | return isRunning;
7 | }
8 |
9 | public void setRunning(boolean isRunning) {
10 | this.isRunning = isRunning;
11 | }
12 |
13 | @Override
14 | public void run() {
15 | System.out.println("进入run了");
16 | while (isRunning == true) {
17 |
18 | }
19 | System.out.println("线程被停止了!");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/SafeLocalVar.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | public class SafeLocalVar {
4 | public void add(String username) {
5 | try {
6 | int num = 0;
7 | if (username.equals("a")) {
8 | num = 100;
9 | System.out.println("a set over");
10 | Thread.sleep(2000);
11 | } else {
12 | num = 200;
13 | System.out.println("b set over");
14 | }
15 | System.out.println(username + " num = " + num);
16 | } catch (InterruptedException e) {
17 | e.printStackTrace();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/test/java/com/sprint/ch01/ThreadMethodsTest.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | import org.junit.Test;
4 | public class ThreadMethodsTest {
5 |
6 | @Test
7 | public void testThreadMethods() throws InterruptedException {
8 | MyThread thread = new MyThread();
9 | thread.start();
10 | System.out.println("currentThread.name:" + Thread.currentThread().getName());
11 | System.out.println("isAlive:" + thread.isAlive());
12 | Thread.sleep(3000); //休眠3秒
13 | System.out.println("getId:" + thread.getId());
14 | Thread.yield();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/UnSafeInitVar.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | public class UnSafeInitVar {
4 | private int num = 0;
5 | public void add(String username) {
6 | try {
7 | if (username.equals("a")) {
8 | num = 100;
9 | System.out.println("a set over!");
10 | Thread.sleep(2000);
11 | } else {
12 | num = 200;
13 | System.out.println("b set over!");
14 | }
15 | System.out.println(username + " num:" + num);
16 | } catch (InterruptedException e) {
17 | e.printStackTrace();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch01/ExceptionThread.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | public class ExceptionThread extends Thread {
4 | @Override
5 | public void run() {
6 | try {
7 | for (int i = 0; i < 500000; i++) {
8 | if (this.interrupted()) {
9 | System.out.println("已经是停止状态了!我要退出");
10 | throw new InterruptedException();
11 | }
12 | System.out.println("i=" + (i+1));
13 | }
14 | } catch (InterruptedException e) {
15 | System.out.println("进ExceptionThread.java类run方法中的catch了!");
16 | e.printStackTrace();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch01/ReturnThread.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch01;
2 |
3 | public class ReturnThread extends Thread {
4 | @Override
5 | public void run() {
6 | try {
7 | for (int i = 0; i < 500000; i++) {
8 | if (this.interrupted()) {
9 | System.out.println("已经是停止状态了!我要退出");
10 | throw new InterruptedException();
11 | }
12 | System.out.println("i=" + (i+1));
13 | }
14 | } catch (InterruptedException e) {
15 | System.out.println("进ExceptionThread.java类run方法中的catch了!");
16 | e.printStackTrace();
17 | }
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/method/MoreObjMoreLock.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.method;
2 |
3 | public class MoreObjMoreLock {
4 | private int num = 0;
5 | public synchronized void add(String username) {
6 | try {
7 | if (username.equals("a")) {
8 | num = 100;
9 | System.out.println("a set over!");
10 | Thread.sleep(2000);
11 | } else {
12 | num = 200;
13 | System.out.println("b set over!");
14 | }
15 | System.out.println(username + " num = " + num);
16 | } catch (InterruptedException e) {
17 | e.printStackTrace();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/lock/FairReentrantLock.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.locks.ReentrantLock;
2 |
3 | public class FairReentrantLock implements Runnable {
4 | private ReentrantLock lock = new ReentrantLock(true);
5 |
6 | @Override
7 | public void run() {
8 | while (true) {
9 | lock.lock();
10 | System.out.println(Thread.currentThread().getName() + "获得锁");
11 | lock.unlock();
12 | }
13 | }
14 |
15 | public static void main(String[] args) {
16 | FairReentrantLock lock = new FairReentrantLock();
17 | Thread t1 = new Thread(lock);
18 | Thread t2 = new Thread(lock);
19 | t1.setName("t1");
20 | t2.setName("t2");
21 | t1.start();
22 | t2.start();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/singleton/StaticCode.java:
--------------------------------------------------------------------------------
1 | public class StaticCode {
2 | public static void main(String[] args) {
3 | MyThread t1 = new MyThread();
4 | MyThread t2 = new MyThread();
5 | MyThread t3 = new MyThread();
6 | t1.start();
7 | t2.start();
8 | t3.start();
9 | }
10 | }
11 |
12 | class MyObject {
13 | private static MyObject instance = null;
14 | private MyObject() {}
15 | static {
16 | instance = new MyObject();
17 | }
18 | public static MyObject getInstance() {
19 | return instance;
20 | }
21 | }
22 |
23 | class MyThread extends Thread {
24 | @Override
25 | public void run() {
26 | for (int i = 0; i < 5; i++) {
27 | System.out.println(MyObject.getInstance().hashCode());
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/add/StateMain.java:
--------------------------------------------------------------------------------
1 | public class StateMain {
2 | public static void main(String[] args) {
3 | try {
4 |
5 | MyThread thread = new MyThread();
6 | System.out.println("main方法中的状态:" + thread.getState());
7 | Thread.sleep(1000);
8 | thread.start();
9 | Thread.sleep(1000);
10 | System.out.println("main方法中的状态:" + thread.getState());
11 | } catch (InterruptedException e) {
12 | e.printStackTrace();
13 | }
14 | }
15 | }
16 |
17 | class MyThread extends Thread {
18 | public MyThread() {
19 | System.out.println("构造方法中的状态:" + Thread.currentThread().getState());
20 | }
21 |
22 | @Override
23 | public void run() {
24 | System.out.println("run方法中的状态:" + Thread.currentThread().getState());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/singleton/HungryModel.java:
--------------------------------------------------------------------------------
1 | //为了描述方便,将类都写在一个文件中的(不推荐使用这种)
2 | public class HungryModel {
3 | public static void main(String[] args) {
4 | MyThread t1 = new MyThread();
5 | MyThread t2 = new MyThread();
6 | MyThread t3 = new MyThread();
7 |
8 | t1.start();
9 | t2.start();
10 | t3.start();
11 | }
12 | }
13 |
14 | class MyObject {
15 |
16 | //确保实例只有一个,可以添加final
17 | private static MyObject myObject = new MyObject();
18 |
19 | private MyObject() {
20 |
21 | }
22 |
23 | public static MyObject getInstance() {
24 | //因为 getInstance没有同步,所以存在线程安全问题
25 | return myObject;
26 | }
27 |
28 | }
29 |
30 | class MyThread extends Thread {
31 |
32 | @Override
33 | public void run() {
34 | System.out.println(MyObject.getInstance().hashCode());
35 | }
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/src/main/java/com/sprint/ch02/block/SynBlock.java:
--------------------------------------------------------------------------------
1 | package com.sprint.ch02.block;
2 |
3 | public class SynBlock {
4 | private String getData1;
5 | private String getData2;
6 |
7 | public void doLongTimeTask() {
8 | try {
9 |
10 | System.out.println("begin task");
11 | Thread.sleep(3000);
12 | String data1 = "长时间处理任务后从远程返回的值 1 threadName=" + Thread.currentThread().getName();
13 | String data2 = "长时间处理任务后从远程返回的值 2 threadName=" + Thread.currentThread().getName();
14 |
15 | synchronized(this) {
16 | getData1 = data1;
17 | getData2 = data2;
18 | }
19 | System.out.println(getData1);
20 | System.out.println(getData2);
21 | System.out.println("begin end");
22 |
23 | } catch (InterruptedException e) {
24 | e.printStackTrace();
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/singleton/InnerClass.java:
--------------------------------------------------------------------------------
1 | //为了描述方便,将类都写在一个文件中的(不推荐使用这种)
2 | public class InnerClass {
3 | public static void main(String[] args) {
4 | MyThread t1 = new MyThread();
5 | MyThread t2 = new MyThread();
6 | MyThread t3 = new MyThread();
7 |
8 | t1.start();
9 | t2.start();
10 | t3.start();
11 | }
12 | }
13 |
14 | class MyObject {
15 |
16 | //在未调用前已经被是加载,并实例
17 | private static class MyObjectHandler {
18 | private static MyObject myObject = new MyObject();
19 | }
20 |
21 | private MyObject() {
22 | }
23 |
24 | public static MyObject getInstance() {
25 | //因为 getInstance没有同步,所以存在线程安全问题
26 | return MyObjectHandler.myObject;
27 | }
28 |
29 | }
30 |
31 | class MyThread extends Thread {
32 |
33 | @Override
34 | public void run() {
35 | System.out.println(MyObject.getInstance().hashCode());
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/lock/TryLockReentrantLock.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.locks.ReentrantLock;
2 | import java.util.concurrent.TimeUnit;
3 | public class TryLockReentrantLock implements Runnable {
4 | private ReentrantLock lock = new ReentrantLock();
5 |
6 | @Override
7 | public void run() {
8 | try {
9 | //其中一个线程获得锁后,占用锁6秒,而另一线程获取锁的时间只有5秒,所以获取不到
10 | if (lock.tryLock(5, TimeUnit.SECONDS)) {
11 | System.out.println(Thread.currentThread().getName() + "成功获取锁");
12 | Thread.sleep(6000);
13 | } else {
14 | System.out.println(Thread.currentThread().getName() + "获取锁失败");
15 | }
16 | } catch (InterruptedException e) {
17 | e.printStackTrace();
18 | } finally {
19 | if (lock.isHeldByCurrentThread()) {
20 | lock.unlock();
21 | }
22 | }
23 | }
24 |
25 | public static void main(String[] args) {
26 | TryLockReentrantLock lock = new TryLockReentrantLock();
27 | Thread t1 = new Thread(lock);
28 | Thread t2 = new Thread(lock);
29 | t1.start();
30 | t2.start();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/thread/readme.md:
--------------------------------------------------------------------------------
1 | # 撸书日志
2 |
3 | ## 第一章 多线程基础(170420)
4 | ## 第二章 对象及变量的并发访问(170421)
5 | 
6 |
7 |
8 | synchronized同步代码块(170423)
9 | - 一半异步,一半同步:不在synchronized中执行的异步,在synchronized中执行的同步
10 | - synchronized代码块间的同步性: 当多个线程访问同一个object中的synchronized代码块时, 最前得到object锁的线程,先执行对应synchronized中的代码,其他执行想执行synchronized代码块的线程进入阻塞状态.必须等待锁释放后才能获取.
11 | - synchronized(this)锁定是当前对象: synchronized代码块间的同步性的原因吧
12 | - synchronized(anyObject)锁定其他对象: 打破synchronized代码块间的同步性,提高效率.这时的anyObject,应在方法内部声明,因方法内的变量是线程安全的
13 | - 静态同步synchronized方法与synchronized(class)代码块:二者作用一样,对Class进行加锁,而Class锁可以对类的所以对象实例起作用
14 | - 避免使用String作为锁对象: String常量有缓存的作用,要避免这种情况带来的问题,建议使用new Object()的方式
15 | - 多线程的死锁: 线程永远得不到锁,相互进行等待
16 |
17 | 
18 |
19 |
20 | volatile :变量在线程之间的可见
21 | - volatile 只能修饰变量
22 | - 非原子性
23 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/singleton/LazyModel.java:
--------------------------------------------------------------------------------
1 | //为了描述方便,将类都写在一个文件中的(不推荐使用这种) \
2 | public class LazyModel {
3 | public static void main(String[] args) {
4 | MyThread t1 = new MyThread();
5 | MyThread t2 = new MyThread();
6 | MyThread t3 = new MyThread();
7 |
8 | t1.start();
9 | t2.start();
10 | t3.start();
11 | }
12 | }
13 |
14 | class MyObject {
15 |
16 | //volatile用于线程可见性
17 | private volatile static MyObject myObject = new MyObject();
18 |
19 | private MyObject() {
20 |
21 | }
22 |
23 | //使用双检测机制解决问题,即保证了不需要同步代码的异步执行性
24 | //又保证了单例的效果
25 | public static MyObject getInstance() {
26 | try {
27 | if (myObject != null) {
28 |
29 | } else {
30 | Thread.sleep(3000);
31 | synchronized (MyObject.class) {
32 | if (myObject == null) {
33 | myObject = new MyObject();
34 | }
35 | }
36 | }
37 | } catch (InterruptedException e) {
38 | e.printStackTrace();
39 | }
40 | return myObject;
41 | }
42 |
43 | }
44 |
45 | class MyThread extends Thread {
46 |
47 | @Override
48 | public void run() {
49 | System.out.println(MyObject.getInstance().hashCode());
50 | }
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/lock/WriteWriteLock.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.locks.ReentrantReadWriteLock;
2 | public class WriteWriteLock {
3 | public static void main(String[] args) {
4 | Service service = new Service();
5 | ThreadA a = new ThreadA(service);
6 | ThreadB b = new ThreadB(service);
7 | a.start();
8 | b.start();
9 | }
10 | }
11 |
12 | class Service {
13 | private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
14 |
15 | public void write() {
16 | try {
17 | lock.writeLock().lock();
18 | System.out.println("获取写锁:" + Thread.currentThread().getName() +
19 | " " + System.currentTimeMillis());
20 | } finally {
21 | lock.writeLock().unlock();
22 | }
23 | }
24 | }
25 |
26 | class ThreadA extends Thread {
27 | Service service;
28 | ThreadA(Service service) {
29 | this.service = service;
30 | }
31 |
32 | @Override
33 | public void run() {
34 | service.write();
35 | }
36 | }
37 |
38 | class ThreadB extends Thread {
39 | Service service;
40 | ThreadB(Service service) {
41 | this.service = service;
42 | }
43 |
44 | @Override
45 | public void run() {
46 | service.write();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/lock/InterruptReentrantLock1.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.locks.ReentrantLock;
2 |
3 | /**
4 | * 测试: lockInterruptibly()(获取锁) 与 interrupt()(中断)搭配,可以很优雅的产生中断响应
5 | * 为了达到深入僵局的目的,并没有释放锁,这样就可以看到很明显的效果了。
6 | * 如果使用lock()(获取锁),程序陷入永久等待。
7 | * 还要说明一点:不同对象的锁是不一致的。
8 | */
9 | public class InterruptReentrantLock1 implements Runnable{
10 |
11 | private ReentrantLock lock = new ReentrantLock();
12 |
13 | @Override
14 | public void run() {
15 | try {
16 |
17 | //lock.lock();
18 | lock.lockInterruptibly();
19 | System.out.println(Thread.currentThread().getName() + "获得lock");
20 | Thread.sleep(500);
21 | System.out.println(Thread.currentThread().getName() + "执行完毕");
22 |
23 | } catch (InterruptedException e) {
24 | e.printStackTrace();
25 | } finally {
26 | // lock.unlock();
27 | // System.out.println(Thread.currentThread().getName() + "释放锁");
28 | }
29 | }
30 |
31 | public static void main(String[] args) throws InterruptedException {
32 | //不同的对象,锁是不一样的
33 | InterruptReentrantLock1 lock1 = new InterruptReentrantLock1();
34 |
35 | Thread t1 = new Thread(lock1);
36 | Thread t2 = new Thread(lock1);
37 | t1.setName("t1");
38 | t2.setName("t2");
39 | t1.start();
40 | t2.start();
41 |
42 | t1.interrupt();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/threadlocal/DateVariableIsolation.java:
--------------------------------------------------------------------------------
1 | import java.util.Date;
2 | public class DateVariableIsolation {
3 | public static void main(String[] args) {
4 | try {
5 | ThreadA a = new ThreadA();
6 | a.start();
7 | Thread.sleep(1000);
8 | ThreadB b = new ThreadB();
9 | b.start();
10 | } catch (InterruptedException e) {
11 | e.printStackTrace();
12 | }
13 | }
14 | }
15 |
16 | class Tool {
17 | public static ThreadLocal t1 = new ThreadLocal<>();
18 | }
19 |
20 | class ThreadA extends Thread {
21 |
22 | @Override
23 | public void run() {
24 | try {
25 | for (int i = 0; i < 20; i++) {
26 | if (Tool.t1.get() == null) {
27 | Tool.t1.set(new Date());
28 | }
29 | System.out.println("A: " + Tool.t1.get().getTime());
30 | Thread.sleep(100);
31 | }
32 | } catch (InterruptedException e) {
33 | e.printStackTrace();
34 | }
35 | }
36 | }
37 |
38 | class ThreadB extends Thread {
39 |
40 | @Override
41 | public void run() {
42 | try {
43 | for (int i = 0; i < 20; i++) {
44 | if (Tool.t1.get() == null) {
45 | Tool.t1.set(new Date());
46 | }
47 | System.out.println("B: " + Tool.t1.get().getTime());
48 | Thread.sleep(100);
49 | }
50 | } catch (InterruptedException e) {
51 | e.printStackTrace();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/SimpleWN.java:
--------------------------------------------------------------------------------
1 | public class SimpleWN {
2 | final static Object object = new Object();
3 | public static class T1 extends Thread {
4 | @Override
5 | public void run() {
6 | synchronized (object) {
7 | System.out.println(System.currentTimeMillis() + ":T1 start!");
8 | try {
9 | System.out.println(System.currentTimeMillis() + ":T1 wait for object ");
10 | object.wait();
11 | Thread.sleep(3000);
12 | System.out.println(System.currentTimeMillis() + ":T1 wait~~~~~~~~`");
13 | } catch (InterruptedException e) {
14 | e.printStackTrace();
15 | }
16 | System.out.println(System.currentTimeMillis() + ":T1 end!");
17 | }
18 | }
19 | }
20 |
21 | public static class T2 extends Thread {
22 |
23 | @Override
24 | public void run() {
25 | synchronized (object) {
26 | System.out.println(System.currentTimeMillis() + ":T2 start! notify onethread");
27 | object.notify();
28 | System.out.println(System.currentTimeMillis() + ":T2: end!");
29 | try {
30 | Thread.sleep(2000);
31 | } catch (InterruptedException e) {
32 |
33 | }
34 | }
35 | }
36 | }
37 |
38 | public static void main(String[] args) throws InterruptedException {
39 | Thread t1 = new T1();
40 | Thread t2 = new T2();
41 | t1.start();
42 | Thread.sleep(1000);
43 | t2.start();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/threadlocal/VariableIsolation.java:
--------------------------------------------------------------------------------
1 | public class VariableIsolation {
2 | public static void main(String[] args) {
3 | try {
4 | ThreadA a = new ThreadA();
5 | ThreadB b = new ThreadB();
6 | a.start();
7 | b.start();
8 | for (int i = 0; i < 100; i++) {
9 | Tool.t1.set("Main:" + (i+1));
10 | System.out.println("Main get value:" + Tool.t1.get());
11 | Thread.sleep(200);
12 | }
13 | } catch (InterruptedException e) {
14 | e.printStackTrace();
15 | }
16 | }
17 | }
18 |
19 | class Tool {
20 | public static ThreadLocal t1 = new ThreadLocal();
21 | }
22 |
23 | class ThreadA extends Thread {
24 |
25 | @Override
26 | public void run() {
27 | try {
28 | for (int i = 0; i < 100; i++) {
29 | Tool.t1.set("ThreadA" + (i+1));
30 | System.out.println("ThreadA get value: " + Tool.t1.get());
31 | Thread.sleep(200);
32 | }
33 | } catch (InterruptedException e) {
34 | e.printStackTrace();
35 | }
36 | }
37 | }
38 |
39 | class ThreadB extends Thread {
40 |
41 | @Override
42 | public void run() {
43 | try {
44 | for (int i = 0; i < 100; i++) {
45 | Tool.t1.set("ThreadB" + (i+1));
46 | System.out.println("ThreadB get value: " + Tool.t1.get());
47 | Thread.sleep(200);
48 | }
49 | } catch (InterruptedException e) {
50 | e.printStackTrace();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/readme.md:
--------------------------------------------------------------------------------
1 | # Java 多线程编程核心技术
2 | > 声明:junit不支持多线程测试,故现弃用.仅提供部分重要代码,省略验证类型代码,建立知识框架
3 | ## 第一章 Java多线程技能
4 | - thread/src/main/java/com/sprint/ch01/下所以文件
5 | - thread/src/test/java/com/sprint/ch01/下所以文件
6 |
7 | 
8 |
9 | ## 第二章 对象及变量的并发访问
10 |
11 | 
12 |
13 |
14 | synchronized同步代码块(170423)
15 | - 一半异步,一半同步:不在synchronized中执行的异步,在synchronized中执行的同步
16 | - synchronized代码块间的同步性: 当多个线程访问同一个object中的synchronized代码块时, 最前得到object锁的线程,先执行对应synchronized中的代码,其他执行想执行synchronized代码块的线程进入阻塞状态.必须等待锁释放后才能获取.
17 | - synchronized(this)锁定是当前对象: synchronized代码块间的同步性的原因吧
18 | - synchronized(anyObject)锁定其他对象: 打破synchronized代码块间的同步性,提高效率.这时的anyObject,应在方法内部声明,因方法内的变量是线程安全的
19 | - 静态同步synchronized方法与synchronized(class)代码块:二者作用一样,对Class进行加锁,而Class锁可以对类的所以对象实例起作用
20 | - 避免使用String作为锁对象: String常量有缓存的作用,要避免这种情况带来的问题,建议使用new Object()的方式
21 | - 多线程的死锁: 线程永远得不到锁,相互进行等待
22 |
23 | 
24 |
25 |
26 | ## 第三章 线程间的通信
27 |
28 | 等待/通知机制(170425)
29 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/lock/ReadReentrantReadWriteLock.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.locks.ReentrantReadWriteLock;
2 | public class ReadReentrantReadWriteLock {
3 |
4 | public static void main(String[] args) {
5 | Service service = new Service();
6 | ThreadA a = new ThreadA(service);
7 | a.setName("A");
8 | ThreadB b = new ThreadB(service);
9 | b.setName("B");
10 | a.start();
11 | b.start();
12 | }
13 | }
14 |
15 | class Service {
16 | private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
17 |
18 | public void read() {
19 |
20 | try {
21 | lock.readLock().lock();//读锁
22 | System.out.println("获得读锁:" + Thread.currentThread().getName() +
23 | " " + System.currentTimeMillis());
24 | } finally {
25 | // lock.readLock().unlock();
26 | // attempt to unlock read lock, not locked by current thread
27 | }
28 |
29 | }
30 | }
31 |
32 | class ThreadA extends Thread {
33 | private Service service;
34 |
35 | public ThreadA(Service service) {
36 | super();
37 | this.service = service;
38 | }
39 |
40 | @Override
41 | public void run() {
42 | try {
43 | service.read();
44 | Thread.sleep(1000);
45 | } catch (InterruptedException e) {
46 | e.printStackTrace();
47 | }
48 | }
49 | }
50 |
51 | class ThreadB extends Thread {
52 | private Service service;
53 |
54 | public ThreadB(Service service) {
55 | super();
56 | this.service = service;
57 | }
58 |
59 | @Override
60 | public void run() {
61 | try {
62 | service.read();
63 | Thread.sleep(1000);
64 | } catch (InterruptedException e) {
65 | e.printStackTrace();
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/singleton/EnumSingleton.java:
--------------------------------------------------------------------------------
1 | import java.sql.Connection;
2 | import java.sql.DriverManager;
3 | import java.sql.SQLException;
4 | public class EnumSingleton {
5 | public static void main(String[] args) {
6 | MyThread t1 = new MyThread();
7 | MyThread t2 = new MyThread();
8 | MyThread t3 = new MyThread();
9 | t1.start();
10 | t2.start();
11 | t3.start();
12 | }
13 | }
14 |
15 | class MyObject {
16 | //遵循职责单一原则
17 | public enum MyEnumSingleton {
18 | connectionFactory;
19 | private Connection connection;
20 | private MyEnumSingleton() {
21 | try {
22 | System.out.println("创建MyObject对象");
23 | String url = "jdbc:mysql//localhost:3306/struts";
24 | String username = "root";
25 | String password = "123456";
26 | String driverName = "com.mysql.jdbc.Driver";
27 | Class.forName(driverName);
28 | connection = DriverManager.getConnection(url, username, password);
29 | } catch (ClassNotFoundException e) {
30 | e.printStackTrace();
31 | } catch (SQLException e) {
32 | e.printStackTrace();
33 | }
34 | }
35 |
36 | public Connection getConnection() {
37 | return connection;
38 | }
39 | }
40 |
41 | public static Connection getConnection() {
42 | return MyEnumSingleton.connectionFactory.getConnection();
43 | }
44 | }
45 |
46 | class MyThread extends Thread {
47 | @Override
48 | public void run() {
49 | for (int i = 0; i < 5; i++) {
50 | System.out.println(MyObject.getConnection().hashCode());
51 | }
52 | }
53 | }
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/lock/InterruptReentrantLock.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.locks.ReentrantLock;
2 |
3 | public class InterruptReentrantLock implements Runnable{
4 |
5 | //目的:使线程获取锁,产生死锁。然后使用interrupt来中断其中一线程.
6 | private ReentrantLock lock1 = new ReentrantLock();
7 | private ReentrantLock lock2 = new ReentrantLock();
8 | int lock;
9 |
10 | public InterruptReentrantLock(int lock) {
11 | this.lock = lock;
12 | }
13 |
14 | @Override
15 | public void run() {
16 | try {
17 | //让lock == 1的线程获取lock1, 让lock == 2 的线程获取lock2,
18 | //在两者为释放锁的情况下,二者相互申请对方的锁,陷入死锁。
19 | if (lock == 1) {
20 | // lock1.lockInterruptibly();
21 | lock1.lock();
22 | System.out.println("线程1已获取lock1");
23 | //确保线程2获取lock2,这里休眠3秒
24 | Thread.sleep(3000);
25 |
26 | //lock2.lockInterruptibly();
27 | lock2.lock();
28 | System.out.println("线程1已获取lock2");
29 | } else {
30 |
31 | //lock2.lockInterruptibly();
32 | lock2.lock();
33 | System.out.println("线程2已获取lock2");
34 | //确保线程1获取lock1.这里休眠3秒
35 | Thread.sleep(3000);
36 |
37 | // lock1.lockInterruptibly();
38 | lock1.lock();
39 | System.out.println("线程2已获取lock1");
40 | }
41 | } catch (InterruptedException e) {
42 | e.printStackTrace();
43 | } finally {
44 | /* if (lock1.isHeldByCurrentThread()) {
45 | lock1.unlock();
46 | }
47 | if (lock2.isHeldByCurrentThread()) {
48 | lock2.unlock();
49 | }
50 | */
51 | }
52 | }
53 |
54 | public static void main(String[] args) throws InterruptedException {
55 | InterruptReentrantLock lock1 = new InterruptReentrantLock(1);
56 | InterruptReentrantLock lock2 = new InterruptReentrantLock(2);
57 |
58 | Thread t1 = new Thread(lock1);
59 | Thread t2 = new Thread(lock2);
60 |
61 | t1.start();
62 | t2.start();
63 |
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/lock/ReadWriteLock.java:
--------------------------------------------------------------------------------
1 | import java.util.concurrent.locks.ReentrantReadWriteLock;
2 | public class ReadWriteLock {
3 |
4 | public static void main(String[] args) {
5 | Service service = new Service();
6 | ThreadA a = new ThreadA(service);
7 | ThreadB b = new ThreadB(service);
8 | a.setName("a");
9 | b.setName("b");
10 | a.start();
11 | b.start();
12 |
13 | }
14 | }
15 |
16 | class Service {
17 | private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
18 |
19 | public void read() {
20 | try {
21 | lock.readLock().lock();
22 | System.out.println("获取读锁:" + Thread.currentThread().getName()
23 | + " " + System.currentTimeMillis());
24 | } finally {
25 | lock.readLock().unlock();
26 | }
27 | }
28 |
29 | public void write() {
30 | try {
31 |
32 | lock.writeLock().lock();
33 | System.out.println("获取写锁:" + Thread.currentThread().getName()
34 | + " " + System.currentTimeMillis());
35 | } finally {
36 | lock.writeLock().unlock();
37 | }
38 | }
39 | }
40 |
41 | class ThreadA extends Thread {
42 | private Service service;
43 |
44 | public ThreadA(Service service) {
45 | super();
46 | this.service = service;
47 | }
48 |
49 | @Override
50 | public void run() {
51 | try {
52 | service.read();
53 | Thread.sleep(1000);
54 | service.write();
55 | } catch (InterruptedException e) {
56 | e.printStackTrace();
57 | }
58 | }
59 | }
60 |
61 | class ThreadB extends Thread {
62 | private Service service;
63 |
64 | public ThreadB(Service service) {
65 | super();
66 | this.service = service;
67 | }
68 |
69 | @Override
70 | public void run() {
71 | try {
72 | service.read();
73 | Thread.sleep(1000);
74 | service.write();
75 | } catch (InterruptedException e) {
76 | e.printStackTrace();
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/等待通知机制.md:
--------------------------------------------------------------------------------
1 | #### 为什么用等待/通知机制?
2 | 线程之间进行通信时,不清楚什么时刻进行通信,通用的方法使用轮询,极大浪费CPU资源,还有可能得不到想要的数据。
3 |
4 | #### Java多线程实现等待/通知机制
5 | Object中的方法:
6 | - wait()使当前线程加入到等待队列里
7 | - notify()随机唤醒等待队列里的一个线程
8 | - notifyAll()唤醒等待队列里的所有线程
9 |
10 | #### wait()和notify()工作原理
11 | wait()和notify()并不是随便就能调用的,调用它们之前必须获取对象的监视器,也就是锁。否则运行期间会报`IllegalMonitorStateException`的
12 | - 获取锁-> obj.wait() ->wait()方法执行完会自动释放锁
13 | - 获取锁-> obj.notify() ->notify()方法执行完不会自动释放锁
14 |
15 | #### 栗子
16 | ```
17 | public class SimpleWN {
18 | final static Object object = new Object();
19 | public static class T1 extends Thread {
20 | @Override
21 | public void run() {
22 | synchronized (object) {
23 | System.out.println(System.currentTimeMillis() + ":T1 start!");
24 | try {
25 | System.out.println(System.currentTimeMillis() + ":T1 wait for object ");
26 | object.wait();
27 | Thread.sleep(3000);
28 | System.out.println(System.currentTimeMillis() + ":T1 wait~~~~~~~~`");
29 | } catch (InterruptedException e) {
30 | e.printStackTrace();
31 | }
32 | System.out.println(System.currentTimeMillis() + ":T1 end!");
33 | }
34 | }
35 | }
36 |
37 | public static class T2 extends Thread {
38 |
39 | @Override
40 | public void run() {
41 | synchronized (object) {
42 | System.out.println(System.currentTimeMillis() + ":T2 start! notify onethread");
43 | object.notify();
44 | System.out.println(System.currentTimeMillis() + ":T2: end!");
45 | try {
46 | Thread.sleep(2000);
47 | } catch (InterruptedException e) {
48 |
49 | }
50 | }
51 | }
52 | }
53 |
54 | public static void main(String[] args) throws InterruptedException {
55 | Thread t1 = new T1();
56 | Thread t2 = new T2();
57 | t1.start();
58 | Thread.sleep(1000);
59 | t2.start();
60 | }
61 | }
62 |
63 | ```
64 | 执行过程:
65 | - object是实例变量,synchronized(object) 获取同一对象的锁
66 | - 首先线程T1获取object锁,之后object执行wait()方法,此时将T1线程加入到等待队列里,释放了object锁
67 | - 接着T2获取了object的锁,随之object调用notify()方法,因等待队列里只要线程T1,所以线程T1被唤醒,此时线程T2还占有object锁,所以等释放了锁,线程T2才能执行。
68 |
69 | 注:在Main方法里sleep(1000)的目的是,防止线程T2先执行,陷入死锁。
70 |
--------------------------------------------------------------------------------
/APUE/chapter-3/file_shared.md:
--------------------------------------------------------------------------------
1 | ## 文件共享
2 |
3 | UNIX 系统支持在不同进程间共享打开文件, 知识点:内核用于所有 I/O 的数据结构、原子操作。
4 |
5 | ### 概念性的 I/O 数据结构
6 |
7 | 内核用于所有 I/O 的数据结构,只是个概念性的,不一定适用,有个大体的轮廓就 OK。
8 |
9 | - 进程表 (process table entry) 中的记录
10 | - 文件表项 (file table entry)
11 | - v节点表项 (v-node table entry)
12 |
13 | 
14 |
15 | 这是一个 `打开文件的内核数据结构` 图。`打开文件` 这个操作是一个进程, 每个进程在进程表中都有一个记录,而 `打开文件进程记录` 中包含一张打开文件描述符表, 包括:
16 |
17 | - 文件描述符标志
18 | - 指向一个文件表项的指针
19 |
20 | 文件描述符表用 Go 抽象如下表示:
21 |
22 | ``` go
23 | type fd struct {
24 | flags int
25 | pointer *FileTableEntry
26 | }
27 | ```
28 |
29 | 代码中 `flags` 的类型是随便定义的(实际我没查),由图中看出 `pointer` 指向文件表项 (file table entry), 内核为所有打开文件维持一张文件表, 每个文件表项包括:
30 |
31 | - 文件状态标志 (读、写、添写、同步和非阻塞)
32 | - 当前文件偏移量
33 | - 指向该文件 v 节点表项的指针
34 |
35 | 文件表项用 Go 抽象如下表示:
36 |
37 | ``` go
38 | type FileTableEntry struct {
39 | status int
40 | offset int
41 | pointer *VNodeTableEntry
42 | }
43 | ```
44 |
45 | 由图中看出 `pointer` 指向v节点表项 (v-node table entry), 每个打开文件都有一个 v 节点结构如下所示:
46 |
47 | - 文件类型和对此文件进行各种操作函数的指针,统称为 v节点信息
48 | - 该文件的 i 节点: 文件所有者、文件长度、指向文件实际数据块在磁盘上所在位置的指针等
49 |
50 | V 节点表项和 i 节点用 Go 抽象如下:
51 |
52 | ``` go
53 | type VNodeTableEntry struct {
54 | information *Information
55 | vData *INode
56 | }
57 |
58 | type INode struct {
59 | owner *Owner
60 | length int
61 | vNodeTableEntry *VNodeTableEntry
62 | }
63 | ```
64 |
65 | 通过这种方式,来加深对 `内核通用 I/O 数据结构` 的理解。
66 |
67 | 如果两个独立进程各自打开同一个文件,则三者关系如下所示:
68 |
69 | 
70 |
71 | ### 原子操作
72 |
73 | 一般而言,原子操作 (atomic operation) 指的是由多步组成的一个操作。如果该操作原子地执行,则要么执行完所有步骤,要么一步也不执行,不可能只执行所有步骤的一个子集。
74 |
75 | ### 函数 dup 和 dup2
76 |
77 | 下面两个函数都可用来复制一个现有的文件描述符。
78 |
79 | ``` c
80 | #include
81 |
82 | int dup(int fd);
83 |
84 | int dup2(int fd, int fd2);
85 | ```
86 |
87 | 上面函数中的参数:
88 |
89 | - fd 表示要复制的文件描述符
90 | - fd2 表示复制后的文件描述符
91 |
92 | `dup2` 函数是可以指定复制后的文件描述符,而 `dup` 是返回当前可用文件描述符中的最小数值。
93 |
94 | 调用 `dup(1)` 函数后,进程表项,文件表,v 节点表,之间的关系图如下:
95 |
96 | 
97 |
98 | 对于传入的参数 fd2, 已经被打开了,会先关闭。知道了这个点,就明白了,下面的操作中会先调用 `close(fd2)`。
99 |
100 | 很不爽了,没找到相应的 Go 的源码。复制一个描述符的另一种方法是使用 `fcntl函数`, `dup2(fd, fd2)` 等效于 `close(fd2)` 和 `fcntl(fd, F_DUPFD, fd2)`, 但不完全等效,因为 `dup2(fd, fd2)` 是个原子操作。
101 |
102 | 目前我先知道 `fcntl函数` 可以改变已经打开文件的属性,就可以啦。
103 |
--------------------------------------------------------------------------------
/Java多线程编程核心技术/lock/20170508.md:
--------------------------------------------------------------------------------
1 | ## 学习ReentrantLock and Condition
2 |
3 | > 说在前面,学习是个螺旋上升的过程,就先暂记录下目前对ReentrantLock和Condition的理解吧
4 |
5 | ## ReentrantLock
6 | ReentrantLock类如其名,就是可以反复的获取该对象中的锁,并不会产生死锁。使用时需要显示获取锁,释放锁等操作。ReentrantLock的特点:
7 | - 优先中断响应
8 | - 锁申请等待时间和轮询锁
9 | - 公平锁
10 |
11 |
12 | #### 优先中断响应
13 | ReentrantLock中`lockInterruptibly()`方法可以优先处理中断响应。
14 | 场景:如果线程1获取了对象锁,并且没有释放,线程2企图进行获取同一个对象锁,此时深入僵局。那么怎么打破僵局呢?线程2调用interrupt()方法,退了一步,就这样化解僵局。
15 |
16 | ```
17 | import java.util.concurrent.locks.ReentrantLock;
18 |
19 | /**
20 | * 测试: lockInterruptibly()(获取锁) 与 interrupt()(中断)搭配,可以很优雅的产生中断响应
21 | * 为了达到深入僵局的目的,并没有释放锁,这样就可以看到很明显的效果了。
22 | * 如果使用lock()(获取锁),程序陷入永久等待。
23 | * 还要说明一点:不同对象的锁是不一致的。
24 | */
25 | public class InterruptReentrantLock1 implements Runnable{
26 |
27 | private ReentrantLock lock = new ReentrantLock();
28 |
29 | @Override
30 | public void run() {
31 | try {
32 |
33 | //lock.lock();
34 | lock.lockInterruptibly();
35 | System.out.println(Thread.currentThread().getName() + "获得lock");
36 | Thread.sleep(500);
37 | System.out.println(Thread.currentThread().getName() + "执行完毕");
38 |
39 | } catch (InterruptedException e) {
40 | e.printStackTrace();
41 | } finally {
42 | // lock.unlock();
43 | // System.out.println(Thread.currentThread().getName() + "释放锁");
44 | }
45 | }
46 |
47 | public static void main(String[] args) throws InterruptedException {
48 | //不同的对象,锁是不一样的
49 | InterruptReentrantLock1 lock1 = new InterruptReentrantLock1();
50 |
51 | Thread t1 = new Thread(lock1);
52 | Thread t2 = new Thread(lock1);
53 | t1.setName("t1");
54 | t2.setName("t2");
55 | t1.start();
56 | t2.start();
57 |
58 | t1.interrupt();
59 | }
60 | }
61 |
62 | ```
63 |
64 | #### 锁申请等待时间和轮询锁
65 | tryLock(timeout, unit): 表示在规定时间内获取锁
66 | tryLock():表示获取锁,并不会等待,轮询。
67 |
68 | ```
69 | import java.util.concurrent.locks.ReentrantLock;
70 | import java.util.concurrent.TimeUnit;
71 | public class TryLockReentrantLock implements Runnable {
72 | private ReentrantLock lock = new ReentrantLock();
73 |
74 | @Override
75 | public void run() {
76 | try {
77 | //其中一个线程获得锁后,占用锁6秒,而另一线程获取锁的时间只有5秒,所以获取不到
78 | if (lock.tryLock(5, TimeUnit.SECONDS)) {
79 | System.out.println(Thread.currentThread().getName() + "成功获取锁");
80 | Thread.sleep(6000);
81 | } else {
82 | System.out.println(Thread.currentThread().getName() + "获取锁失败");
83 | }
84 | } catch (InterruptedException e) {
85 | e.printStackTrace();
86 | } finally {
87 | if (lock.isHeldByCurrentThread()) {
88 | lock.unlock();
89 | }
90 | }
91 | }
92 |
93 | public static void main(String[] args) {
94 | TryLockReentrantLock lock = new TryLockReentrantLock();
95 | Thread t1 = new Thread(lock);
96 | Thread t2 = new Thread(lock);
97 | t1.start();
98 | t2.start();
99 | }
100 |
101 | }
102 |
103 | ```
104 | #### 公平锁
105 | 线程申请锁,并不是按照时间顺序来的,而是随机的,已经申请过该锁的线程,该锁被该线程再次获取的几率比其他线程要高,我觉得像“上帝的原则”,ReentrantLock的一个构造器`ReentrantLock(boolean fair)`, 当fair为true时,这时锁变身为公平锁,会根据线程的获取请求时间来获取锁。
106 | ```
107 | //因为fair默认为false,所以如果想使用公平锁,需使fair为true
108 | private ReentrantLock lock = new ReentrantLock(true);
109 | ```
110 |
111 | ## Condition
112 | 在Synchronized控制下,我们可以使用Object.wait()和Object.notify()或Object.nofifyAll()来进行等待/通知。还有这个两个方法只能在Synchronized内是使用。那么怎么在ReentrantLock中使用等待/通知呢?这是Condition就登场了,ReentrantLock中`newCodition()`方法:Returns a Codition instance for use with this Lock intance. `Condition`接口中存在如下方法:
113 | - await() : 使当前线程进入等待,并释放当前锁
114 | - await(timeout, unit) : 设置等待时间,在此时间段内进入等待状态
115 | - signal(): 在等待队列里随机唤性一个线程线程
116 | - signalAll(): 唤醒等待队列中的所有线程
117 |
118 | `Condition`接口中的详情,还请移驾官方文档。
119 |
--------------------------------------------------------------------------------
/APUE/chapter-4/file_property.md:
--------------------------------------------------------------------------------
1 | ## 文件属性
2 |
3 | 当我们想获取有关文件信息的时候,该怎么办? 当然是调用 `stat` 函数啦。
4 |
5 | 在 APUE 中给出了 4 个 `stat`函数如下所示:
6 |
7 | ``` c
8 | #include
9 |
10 | int stat(const char *restrict pathname, struct stat *restrict buf);
11 |
12 | int fstat(int fd, struct stat *buf);
13 |
14 | int lstat(const char *restrict pathname, struct stat *restrict buf);
15 |
16 | int fstatat(int fd, const char *restrict pathname, struct stat *restrict buf, int flag);
17 | ```
18 |
19 | 上面函数中的参数:
20 | - pathname 表示文件地址
21 | - fd 表示文件描述符
22 | - buf 表示一个指针,指向我们提供的结构体
23 | - flag 表示是否跟随着一个符号链接
24 |
25 | 主要 Get 到 `stat` 函数用于获取文件结构信息, 就好。
26 |
27 | 那么用 Go 来获取下文件结构信息:
28 |
29 | ``` go
30 | func Stat(name string) (FileInfo, error)
31 | ```
32 |
33 | 上面函数中的参数:
34 | - name 表示文件地址
35 | - FileInfo 表示文件结构信息
36 |
37 | 上面的 `Stat` 函数位于 `os` 包下,重要就是 `FileInfo` 这个数据结构,源码如下:
38 |
39 | ``` go
40 | type FileInfo interface {
41 | Name() string // base name of the file
42 | Size() int64 // length in bytes for regular files; system-dependent for others
43 | Mode() FileMode // file mode bits
44 | ModTime() time.Time // modification time
45 | IsDir() bool // abbreviation for Mode().IsDir()
46 | Sys() interface{} // underlying data source (can return nil)
47 | }
48 | ```
49 |
50 | 上面的基本类型都不陌生,需要看看 `FileMode` 的类型:
51 |
52 | ``` go
53 | type FileMode uint32
54 |
55 | // The defined file mode bits are the most significant bits of the FileMode.
56 | // The nine least-significant bits are the standard Unix rwxrwxrwx permissions.
57 | // The values of these bits should be considered part of the public API and may be
58 | // used in wire protocols or disk representations: they must not be changed,
59 | // although new bits might be added.
60 | const (
61 | // The single letters are the abbreviations
62 | // used by the String method's formatting.
63 | ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory
64 | ModeAppend // a: append-only
65 | ModeExclusive // l: exclusive use
66 | ModeTemporary // T: temporary file; Plan 9 only
67 | ModeSymlink // L: symbolic link
68 | ModeDevice // D: device file
69 | ModeNamedPipe // p: named pipe (FIFO)
70 | ModeSocket // S: Unix domain socket
71 | ModeSetuid // u: setuid
72 | ModeSetgid // g: setgid
73 | ModeCharDevice // c: Unix character device, when ModeDevice is set
74 | ModeSticky // t: sticky
75 |
76 | // Mask for the type bits. For regular files, none will be set.
77 | ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
78 |
79 | ModePerm FileMode = 0777 // Unix permission bits
80 | )
81 | ```
82 |
83 | 这段代码引出好几个知识点,罗列如下:
84 | - 文件类型
85 | - 文件模式字(st_mode)
86 | - 文件访问权限
87 |
88 | #### 文件类型
89 |
90 | 1. 普通文件(regular file),包含各种数据的文件。
91 | 2. 目录文件 (directory file), 原来目录也是一种文件。
92 | 3. 块特殊文件 (block special file), 这种类型的文件提供对设备带缓冲的访问 (没用过)。
93 | 4. 字符特殊文件 (character special file), 这种类型的文件不提供对设备带缓冲的访问。
94 | 5. FIFO 这种文件用于进程间通信。
95 | 6. 套接字(socket), 这种用于进程间的网络通信。
96 | 7. 符号链接 (symbolicc link),这种文件指向另一文件。
97 |
98 | #### 文件模式字(st_mode)
99 |
100 | 如上代码中的常量定义,可知:
101 |
102 | 1. ModeDir ---> 目录文件
103 | 2. Symlink ---> 符号链接文件
104 | 3. Device ---> 块特殊文件 (猜)
105 | 4. NamePipe ---> FIFO
106 | 5. Socket ---> 套接字
107 | 6. CharDevice ---> 字符特殊文件
108 |
109 | 有关 `普通文件` 查看了 Go 标准库,代码如下:
110 |
111 | ``` go
112 | // IsRegular reports whether m describes a regular file.
113 | // That is, it tests that no mode type bits are set.
114 | func (m FileMode) IsRegular() bool {
115 | return m&ModeType == 0
116 | }
117 | ```
118 |
119 | !ModeType ---> 普通文件
120 |
121 | #### 文件访问权限
122 |
123 | 需要了解标准的 Unix 权限 `rwxrwxrwx`, 也是 `ModePerm` 这个 Value, `rwxrwxrwx` 分别对应着 `owner`, `group`, `other`。
124 |
--------------------------------------------------------------------------------
/APUE/chapter-3/basic_file_io.md:
--------------------------------------------------------------------------------
1 | ## 基本的文件 I/O
2 |
3 | 我想 open, read, write, lseek, close 这个几个操作就满足了对文件操作的基本需求。当然了,我也是看书是这么写的。
4 |
5 | 每个语言基本都有对应的函数或方法,我们调用就行,在这种情况下,我们可以理解成 -> `语言就是个工具`。我比较偏向 Go 的风格,所以这里我以 Go 的函数库为例,但在介绍其之前,要明白一个概念:文件描述符。
6 |
7 | 画中重点了:
8 |
9 | 对于内核而言, 所有打开的文件都通过文件描述符引用。文件描述符是一个非负整数。
10 |
11 | 对上面的描述还是有点模糊呢?
12 |
13 | 当打开一个现有文件或创建一个新的文件时,内核向进程返回一个 `文件描述符`。
14 |
15 | 当读、写一个文件时,使用 open 或 create 返回的 `文件描述符` 标识该文件,将 `文件描述符` 作为参数传递给 read 或 write。
16 |
17 | 通常用变量 `fd` 来表示文件描述符 (file descripter)
18 |
19 | ### 函数 open 和 openat & 函数 create
20 |
21 | 调用 open 或 openat 函数就可以打开或创建一个文件。
22 |
23 | ``` c
24 | #include
25 |
26 | int open(const char *path, int oflag, ... /* mode_t mode */);
27 |
28 | int openat(int fd, const char *path, int oflag, ... /* mode_t mode */);
29 | ```
30 |
31 | 调用 create 函数创建一个新文件。
32 |
33 | ``` go
34 | #include
35 |
36 | int create(const char *path, mode_t mode);
37 | ```
38 |
39 | 上面函数中的参数:
40 | - path 是要打开或创建文件的名字
41 | - oflag 是对文件进行哪些操作的 flag, 例如:O_RDWR|O_CREATE|O_TRUNC
42 | - mode 指定该文件的访问权限位
43 | - fd 表示文件描述符
44 |
45 | 在这里罗列了 Go 中对文件进行哪些操作的 flags:
46 |
47 | ``` go
48 | // Flags to OpenFile wrapping those of the underlying system. Not all
49 | // flags may be implemented on a given system.
50 | const (
51 | O_RDONLY int = syscall.O_RDONLY // open the file read-only.
52 | O_WRONLY int = syscall.O_WRONLY // open the file write-only.
53 | O_RDWR int = syscall.O_RDWR // open the file read-write.
54 | O_APPEND int = syscall.O_APPEND // append data to the file when writing.
55 | O_CREATE int = syscall.O_CREAT // create a new file if none exists.
56 | O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist
57 | O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
58 | O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
59 | )
60 | ```
61 |
62 | 如何用 Go 打开或创建一个文件:
63 |
64 | ``` go
65 | // Open file
66 | func Open(name string) (*File, error) {
67 | return OpenFile(name, O_RDONLY, 0)
68 | }
69 |
70 | // Create file
71 | func Create(name string) (*File, error) {
72 | return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
73 | }
74 | ```
75 |
76 | 通过观察源码,得知二者都是调用 `OpenFile` 函数,只是 flag, mode 不同。
77 |
78 | ``` go
79 | // OpenFile is the generalized open call; most users will use Open
80 | // or Create instead. It opens the named file with specified flag
81 | // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
82 | // methods on the returned File can be used for I/O.
83 | // If there is an error, it will be of type *PathError.
84 | func OpenFile(name string, flag int, perm FileMode) (*File, error) {
85 | chmod := false
86 | if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 {
87 | if _, err := Stat(name); IsNotExist(err) {
88 | chmod = true
89 | }
90 | }
91 |
92 | var r int
93 | for {
94 | var e error
95 | r, e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
96 | if e == nil {
97 | break
98 | }
99 |
100 | // On OS X, sigaction(2) doesn't guarantee that SA_RESTART will cause
101 | // open(2) to be restarted for regular files. This is easy to reproduce on
102 | // fuse file systems (see http://golang.org/issue/11180).
103 | if runtime.GOOS == "darwin" && e == syscall.EINTR {
104 | continue
105 | }
106 |
107 | return nil, &PathError{"open", name, e}
108 | }
109 |
110 | // open(2) itself won't handle the sticky bit on *BSD and Solaris
111 | if chmod {
112 | Chmod(name, perm)
113 | }
114 |
115 | // There's a race here with fork/exec, which we are
116 | // content to live with. See ../syscall/exec_unix.go.
117 | if !supportsCloseOnExec {
118 | syscall.CloseOnExec(r)
119 | }
120 |
121 | return newFile(uintptr(r), name), nil
122 | }
123 | ```
124 |
125 | 当读上面这段代码时,`supportsCreatedWithStickyBit` 这就卡住啦,知识点就是 `StickyBit` (粘着位)
126 |
127 | 了解下 `StickyBit` (粘着位):
128 |
129 | 在 UNIX 还没有使用请求分页式技术的早期版本中,如果 `可执行文件` 设置了 `StickyBit`,在执行该文件结束时,程序的正文部分的一个副本仍被保存在交换区,以便下次执行时,可以迅速装入内存。然而现今的 UNIX 中大多数配置了虚拟存储系统以及快速文件系统,所以不再需要使用该技术啦。
130 |
131 | 在 `OpenFile` 函数源码中, 常量`supportsCreatedWithStickyBit` 在 Ubuntu 16.04 环境下的值是 true, 故那部分代码不会被执行。所以在 Ubuntu 16.04 环境下的开发者可以不用去了解 `if !supportsCreatedWithStickyBit ... ` 代码块。由于使用 Ubuntu 16.04 的缘故,所以 `OpenFile` 函数可以简化如下:
132 |
133 | ``` go
134 | // OpenFile is the generalized open call; most users will use Open
135 | // or Create instead. It opens the named file with specified flag
136 | // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
137 | // methods on the returned File can be used for I/O.
138 | // If there is an error, it will be of type *PathError.
139 | func OpenFile(name string, flag int, perm FileMode) (*File, error) {
140 | var r int
141 | for {
142 | var e error
143 | r, e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
144 | if e == nil {
145 | break
146 | }
147 | return nil, &PathError{"open", name, e}
148 | }
149 | return newFile(uintptr(r), name), nil
150 | }
151 | ```
152 |
153 | 简化后的代码,发现核心代码就是:`syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))`, 触发系统调用。在深入了解之前,咱先把 `syscallMode(prem)` 解决掉,扫除障碍。
154 |
155 | ``` go
156 | // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
157 | func syscallMode(i FileMode) (o uint32) {
158 | o |= uint32(i.Perm())
159 | if i&ModeSetuid != 0 {
160 | o |= syscall.S_ISUID
161 | }
162 | if i&ModeSetgid != 0 {
163 | o |= syscall.S_ISGID
164 | }
165 | if i&ModeSticky != 0 {
166 | o |= syscall.S_ISVTX
167 | }
168 | // No mapping for Go's ModeTemporary (plan9 only).
169 | return
170 | }
171 | ```
172 |
173 | 让我们了解下 `FileMode`,源码是这样定义的 `type FileMode uint32`, 并通过查看源码得值 `i.Perm()` 等价于 `i & 0777`, 并通过了解 `Open` 的 mode 为 0 ,syscallMode(0) == 0 ;`Create` 中 mode 为 0666, syscallMode(0666) == 438
174 |
175 | > Tips: 一开始因为 posix 结尾的文件是 “posix系统” (不存在的) 下调用的,查了之后,才知道是 unix 系统下调用的。
176 |
177 | 那让我们关注点切换到 `syscall.Open(name, mode, prem)` 上, 类似 c 中的方法吧!深度的话先挖到这个地方。
178 |
179 | 让我们回到简化后的 `OpenFile` 剩余的知识点: `PathError`, `NewFile(uintptr(r), name)`。
180 |
181 | `PathError` 的源码如下:
182 |
183 | ``` go
184 | // PathError records an error and the operation and file path that caused it.
185 | type PathError struct {
186 | Op string
187 | Path string
188 | Err error
189 | }
190 |
191 | func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
192 | ```
193 |
194 | `error` 是个接口, 只要实现了 `Error` 方法就 OK.
195 |
196 | `uintptr(r)` 中 `uintptr` 定义如下:
197 |
198 | ``` go
199 | // uintptr is an integer type that is large enough to hold the bit pattern of
200 | // any pointer.
201 | type uintptr uintptr
202 | ```
203 |
204 | `uintptr(r)` 中 `r` 是个 `int` 类型。
205 |
206 | 看下 `NewFile` 这个函数是怎么定义的,源码如下:
207 |
208 | ``` go
209 | // NewFile returns a new File with the given file descriptor and name.
210 | func NewFile(fd uintptr, name string) *File {
211 | fdi := int(fd)
212 | if fdi < 0 {
213 | return nil
214 | }
215 | f := &File{&file{fd: fdi, name: name}}
216 | runtime.SetFinalizer(f.file, (*file).close)
217 | return f
218 | }
219 | ```
220 |
221 | 上面函数中 `fd` 经过一轮回又回到了 `int` 类型。`File` 是 `file` 类型的封装,源码如下:
222 |
223 | ``` go
224 | // File represents an open file descriptor.
225 | type File struct {
226 | *file // os specific
227 | }
228 |
229 | // file is the real representation of *File.
230 | // The extra level of indirection ensures that no clients of os
231 | // can overwrite this data, which could cause the finalizer
232 | // to close the wrong file descriptor.
233 | type file struct {
234 | fd int
235 | name string
236 | dirinfo *dirInfo // nil unless directory being read
237 | }
238 | ```
239 |
240 | 上面函数中 `runtime.SetFinalizer(f.file, (*file).close)`, 类型 c/c++ 中的 `析构函数` 吧!(挖, 先这吧)
241 |
242 | ### 函数 close
243 |
244 | 调用 `close` 函数关闭一个打开文件。
245 |
246 | ``` c
247 | #include
248 |
249 | int close(int fd);
250 | ```
251 |
252 | 如何用 Go 来关闭一个文件呢?
253 |
254 | ``` go
255 | // Close closes the File, rendering it unusable for I/O.
256 | // It returns an error, if any.
257 | func (f *File) Close() error {
258 | if f == nil {
259 | return ErrInvalid
260 | }
261 | return f.file.close()
262 | }
263 |
264 | func (file *file) close() error {
265 | if file == nil || file.fd == badFd {
266 | return syscall.EINVAL
267 | }
268 | var err error
269 | if e := syscall.Close(file.fd); e != nil {
270 | err = &PathError{"close", file.name, e}
271 | }
272 | file.fd = -1 // so it can't be closed again
273 |
274 | // no need for a finalizer anymore
275 | runtime.SetFinalizer(file, nil)
276 | return err
277 | }
278 | ```
279 |
280 | 从上面的代码中可见,`syscall.Close(file.fd)` 类似 `c` 中的 `close`,起着关键性的作用。其源码如下:
281 |
282 | ``` go
283 | // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
284 |
285 | func Close(fd int) (err error) {
286 | _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
287 | if e1 != 0 {
288 | err = errnoErr(e1)
289 | }
290 | return
291 | }
292 | ```
293 |
294 | `Syscall(SYS_CLOSE, uintptr(fd), 0, 0)` 估计是更底层的调用了,就不再挖啦。
295 |
296 | ### 函数 lseek
297 |
298 | 调用 lseek 显式地为一个打开文件设置偏移量。
299 |
300 | ``` c
301 | #include
302 |
303 | off_t lseek(int fd, off_t offset, int whence);
304 | ```
305 |
306 | 上面函数中的参数:
307 | - fd 表示文件描述符
308 | - 若 whence 是 SEEK_SET, 则将该文件的偏移量设置为`距文件开始处 offset` 个字节
309 | - 若 whence 是 SEEK_CUR, 则将该文件的偏移量设置为`其当前值加 offset, offset `可正可负
310 | - 若 whence 是 SEEK_END, 则将该文件的偏移量设置为`文件长度加 offset, offset `可正可负
311 |
312 | 这些参数是在 Go 也适用的, 但是这种方式,已经在 Go 中弃用啦,详情如下:
313 |
314 | ``` go
315 | // Seek whence values.
316 | //
317 | // Deprecated: Use io.SeekStart, io.SeekCurrent, and io.SeekEnd.
318 | const (
319 | SEEK_SET int = 0 // seek relative to the origin of the file
320 | SEEK_CUR int = 1 // seek relative to the current offset
321 | SEEK_END int = 2 // seek relative to the end
322 | )
323 | ```
324 |
325 | 如何用 Go 来设置文件的偏移量呢?
326 |
327 | ``` go
328 | // Seek sets the offset for the next Read or Write on file to offset, interpreted
329 | // according to whence: 0 means relative to the origin of the file, 1 means
330 | // relative to the current offset, and 2 means relative to the end.
331 | // It returns the new offset and an error, if any.
332 | // The behavior of Seek on a file opened with O_APPEND is not specified.
333 | func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
334 | if err := f.checkValid("seek"); err != nil {
335 | return 0, err
336 | }
337 | r, e := f.seek(offset, whence)
338 | if e == nil && f.dirinfo != nil && r != 0 {
339 | e = syscall.EISDIR
340 | }
341 | if e != nil {
342 | return 0, f.wrapErr("seek", e)
343 | }
344 | return r, nil
345 | }
346 | ```
347 |
348 | 可见 `f.seek(offset, whence)` 起着关键性的作用。
349 |
350 | ``` go
351 | // seek sets the offset for the next Read or Write on file to offset, interpreted
352 | // according to whence: 0 means relative to the origin of the file, 1 means
353 | // relative to the current offset, and 2 means relative to the end.
354 | // It returns the new offset and an error, if any.
355 | func (f *File) seek(offset int64, whence int) (ret int64, err error) {
356 | return syscall.Seek(f.fd, offset, whence)
357 | }
358 | ```
359 |
360 | `syscall.Seek(f.fd, offset, whence)` 发起了一个系统调用,再挖就到了再底层和汇编啦。
361 |
362 | ### 函数 read
363 |
364 | 调用 read 函数从打开文件中读取数据。
365 |
366 | ``` c
367 | #include
368 |
369 | ssize_t read(int fd, void *buf, size_t nbytes);
370 | ```
371 |
372 | 上面函数中的参数:
373 |
374 | - fd 表示文件描述符
375 | - buf 要读的文件,类型是通用的指针
376 | - nbytes 表示读取的字节数
377 |
378 | 如果 read 成功, 则返回读到的字节数,如已到达文件的尾端,则返回 0。
379 |
380 | Tips: 有多种情况可能使实际读到的字节数少于要求读的字节数。
381 |
382 | 如何用 Go 从打开文件中读取数据呢?
383 |
384 | ``` go
385 | // Read reads up to len(b) bytes from the File.
386 | // It returns the number of bytes read and any error encountered.
387 | // At end of file, Read returns 0, io.EOF.
388 | func (f *File) Read(b []byte) (n int, err error) {
389 | if err := f.checkValid("read"); err != nil {
390 | return 0, err
391 | }
392 | n, e := f.read(b)
393 | return n, f.wrapErr("read", e)
394 | }
395 | ```
396 |
397 | 其底层代码如上,递归查看 `go package`。
398 |
399 | ### 函数 write
400 |
401 | 调用 write 函数向打开文件写数据。
402 |
403 | ``` c
404 | #include
405 |
406 | ssize_t write(int fd, const void *buf, size_t nbytes);
407 | ```
408 |
409 | 上面函数的参数:
410 |
411 | - fd 表示文件描述符
412 | - buf 要写的文件,类型是通用的指针
413 | - nbytes 表示读取的字节数
414 |
415 | 如果 write 成功, 则返回读到的字节数,如已到达文件的尾端,则返回 0。
416 |
417 |
418 | 如何用 Go 向打开文件中写入数据?
419 |
420 | ``` go
421 | func (f *File) Write(b []byte) (n int, err error)
422 | ```
423 |
424 | ### 结束
425 |
426 | 如果光看 APUE, 前几页还可以,慢慢就看不下去了,Go 的 lib 基本跟 unix 的接口相似,就结合着 Go 的源码一起看了,只要有个大概的框架就 OK, 随着往后慢慢深入,会有更深的理解。
427 |
--------------------------------------------------------------------------------