├── 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 | ![synchronizedMethod.jpg](http://upload-images.jianshu.io/upload_images/2031765-292516d632cbf4d1.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | ![synchronizedBlock.jpg](http://upload-images.jianshu.io/upload_images/2031765-b3a9ba1f37e9839e.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | ![多线程基础.jpg](http://upload-images.jianshu.io/upload_images/2031765-dd8c04aedbdaaeb4.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 8 | 9 | ## 第二章 对象及变量的并发访问 10 | 11 | ![synchronizedMethod.jpg](http://upload-images.jianshu.io/upload_images/2031765-292516d632cbf4d1.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | ![synchronizedBlock.jpg](http://upload-images.jianshu.io/upload_images/2031765-b3a9ba1f37e9839e.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | ![打开文件的内核数据结构](./3-7.jpg) 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 | ![两个独立进程打开同一个文件](3-8.png) 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 | ![dup(1) 后的内核数据结构](3-9.jpg) 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 | --------------------------------------------------------------------------------