1、查看线程存活状态
Thread.isAlive()
Thread.getName()

public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 10; i++) {printMsg();}}public static void printMsg(){Thread thread = Thread.currentThread();//Thread.getName()  获取线程名称System.out.println("name=["+thread.getName()+"]");}public static void main(String[] args) {MyThread myThread = new MyThread();myThread.setName("MyThread"); //修改线程名称System.out.println("before start(),the Thread Alive = " + myThread.isAlive());//判断线程存活状态myThread.start();System.out.println("just after start(),the Thread Alive = " + myThread.isAlive());for (int i = 0; i < 10; i++) {printMsg();}System.out.println("the end of Thread Alive = " + myThread.isAlive());}
}

输出结果

before start(),the Thread Alive = false
just after start(),the Thread Alive = true
name=[main]
name=[main]
name=[main]
name=[main]
name=[MyThread]
name=[main]
name=[main]
name=[main]
name=[main]
name=[main]
name=[main]
name=[MyThread]
the end of Thread Alive = true
name=[MyThread]
name=[MyThread]
name=[MyThread]
name=[MyThread]
name=[MyThread]
name=[MyThread]
name=[MyThread]
name=[MyThread]

2、多线程同步锁
有三种同步锁:synchronize锁,lock锁,volatile锁

  1. synchronize锁是一般情况下Java多线程开发所使用的最常用同步锁。
  2. lock锁同样是常见同步锁。
  3. volatile锁是一种轻量同步锁,能够减轻同步锁所带来的的资源消耗,但只能所用在变量上。

lock锁与synchronize锁的区别:

  1. 两者都是可重入锁,自己可以再次获取自己的内部锁。
  2. synchronized是依赖于虚拟机的,而Lock锁依赖JDK。
  3. synchronized锁可以自动释放锁,而Lock锁必须要手动释放锁。
  4. synchronized锁的两个线程1和线程2,如果当前线程1获得锁,线程2等待,如果线程1阻塞,线程2会一致等待下去,而Lock锁不一定会等下去,如果尝试获几次取不到锁,线程2可以不用一直等待就结束了。

synchronize锁的使用场景:卖票

class MyThread extends Thread{public static void main(String[] args) {Ticket ticket=new Ticket();Thread thread = new Thread(ticket,"售票员小张");thread.start();Thread thread1 = new Thread(ticket,"售票员小刘");thread1.start();}
}
//票务系统
class Ticket implements Runnable {//总票数private int ticketCount = 40;@Overridepublic void run() {while (true) {//对票务类进行同步锁,避免线程产生脏数据synchronized (Ticket.class) {if (ticketCount > 0) {try {//小张在出票的时候被领导叫走了//这个时候呢,小刘也要卖这张票//线程睡眠是在模拟网络延迟的情况Thread.sleep(100);} catch (Exception e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在售票,剩余" + (--ticketCount));}}}}
}

输出结果

售票员小张正在售票,剩余39
售票员小张正在售票,剩余38
售票员小张正在售票,剩余37
售票员小张正在售票,剩余36
售票员小刘正在售票,剩余35
售票员小刘正在售票,剩余34
售票员小刘正在售票,剩余33
售票员小刘正在售票,剩余32
售票员小刘正在售票,剩余31
售票员小刘正在售票,剩余30
售票员小刘正在售票,剩余29
售票员小刘正在售票,剩余28
售票员小刘正在售票,剩余27
售票员小刘正在售票,剩余26
售票员小刘正在售票,剩余25
售票员小刘正在售票,剩余24
售票员小刘正在售票,剩余23
售票员小刘正在售票,剩余22
售票员小刘正在售票,剩余21
售票员小刘正在售票,剩余20
售票员小张正在售票,剩余19
售票员小张正在售票,剩余18
售票员小刘正在售票,剩余17
售票员小刘正在售票,剩余16
售票员小刘正在售票,剩余15
售票员小刘正在售票,剩余14
售票员小刘正在售票,剩余13
售票员小刘正在售票,剩余12
售票员小刘正在售票,剩余11
售票员小刘正在售票,剩余10
售票员小刘正在售票,剩余9
售票员小刘正在售票,剩余8
售票员小刘正在售票,剩余7
售票员小刘正在售票,剩余6
售票员小刘正在售票,剩余5
售票员小刘正在售票,剩余4
售票员小刘正在售票,剩余3
售票员小刘正在售票,剩余2
售票员小张正在售票,剩余1
售票员小刘正在售票,剩余0

Lock锁使用场景:卖票

class MyThread extends Thread{public static void main(String[] args) {//创建锁对象Lock lock=new ReentrantLock();//创建要执行的任务Ticket ticket=new Ticket(lock);//创建线程并开启线程Thread t1=new Thread(ticket,"售票员张小飞");t1.start();Thread t2=new Thread(ticket,"售票员关小羽");t2.start();}
}class Ticket implements Runnable {private Lock lock;private int count = 40;public Ticket(Lock lock) {this.lock = lock;}@Overridepublic void run() {while (true) {//使用lock锁进行加锁lock.lock();if (count > 0) {try {Thread.sleep(100);System.out.println(Thread.currentThread().getName() + "售出一张票,剩余" + (--count) + "张");} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}else{System.out.println("售票结束");System.exit(0);}}
}

输出结果

售票员张小飞售出一张票,剩余39张
售票员张小飞售出一张票,剩余38张
售票员张小飞售出一张票,剩余37张
售票员张小飞售出一张票,剩余36张
售票员张小飞售出一张票,剩余35张
售票员张小飞售出一张票,剩余34张
售票员张小飞售出一张票,剩余33张
售票员张小飞售出一张票,剩余32张
售票员张小飞售出一张票,剩余31张
售票员张小飞售出一张票,剩余30张
售票员张小飞售出一张票,剩余29张
售票员张小飞售出一张票,剩余28张
售票员张小飞售出一张票,剩余27张
售票员张小飞售出一张票,剩余26张
售票员张小飞售出一张票,剩余25张
售票员张小飞售出一张票,剩余24张
售票员张小飞售出一张票,剩余23张
售票员张小飞售出一张票,剩余22张
售票员张小飞售出一张票,剩余21张
售票员张小飞售出一张票,剩余20张
售票员张小飞售出一张票,剩余19张
售票员张小飞售出一张票,剩余18张
售票员张小飞售出一张票,剩余17张
售票员张小飞售出一张票,剩余16张
售票员张小飞售出一张票,剩余15张
售票员张小飞售出一张票,剩余14张
售票员张小飞售出一张票,剩余13张
售票员张小飞售出一张票,剩余12张
售票员张小飞售出一张票,剩余11张
售票员张小飞售出一张票,剩余10张
售票员张小飞售出一张票,剩余9张
售票员张小飞售出一张票,剩余8张
售票员张小飞售出一张票,剩余7张
售票员张小飞售出一张票,剩余6张
售票员张小飞售出一张票,剩余5张
售票员张小飞售出一张票,剩余4张
售票员张小飞售出一张票,剩余3张
售票员张小飞售出一张票,剩余2张
售票员张小飞售出一张票,剩余1张
售票员张小飞售出一张票,剩余0张
售票结束

我们可以看到使用Lock锁之后,另一线程无法调用run方法,一直处于等待,在尝试运行run()方法几次之后,结束了另一进程。

3、线程优先级
setPriority(int priority)

class MyThread extends Thread{private int countDown = 5;private volatile double d = 0;  //同步变量dpublic MyThread(int priority) {setPriority(priority);  //设置当前线程优先级start();    //开启当前线程}@Overridepublic String toString() {return super.toString() + ":" + countDown;}@Overridepublic void run() {synchronized(this){while (true){for (int i = 0; i < 5000; i++) {d = d + (Math.PI + Math.E) / i;System.out.println(this);if (--countDown == 0) return;}}}}public static void main(String[] args) {new MyThread(Thread.MAX_PRIORITY);for (int i = 1; i < 5; i++)new MyThread(Thread.MIN_PRIORITY);}
}

输出结果

Thread[Thread-0,10,main]:5
Thread[Thread-1,1,main]:5
Thread[Thread-2,1,main]:5
Thread[Thread-3,1,main]:5
Thread[Thread-1,1,main]:4
Thread[Thread-0,10,main]:4
Thread[Thread-1,1,main]:3
Thread[Thread-3,1,main]:4
Thread[Thread-4,1,main]:5
Thread[Thread-2,1,main]:4
Thread[Thread-4,1,main]:4
Thread[Thread-3,1,main]:3
Thread[Thread-1,1,main]:2
Thread[Thread-0,10,main]:3
Thread[Thread-1,1,main]:1
Thread[Thread-3,1,main]:2
Thread[Thread-4,1,main]:3
Thread[Thread-2,1,main]:3
Thread[Thread-4,1,main]:2
Thread[Thread-3,1,main]:1
Thread[Thread-0,10,main]:2
Thread[Thread-4,1,main]:1
Thread[Thread-2,1,main]:2
Thread[Thread-0,10,main]:1
Thread[Thread-2,1,main]:1

4、死锁问题及解决方案

  • 死锁的情形: 多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
  • 死锁产生必要条件:
    1. 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用。
    2. 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
    3. 请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
    4. 循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
  • 解决死锁方案
    一种是synchronized同步锁,另一种是Lock显式锁
    为避免死锁,采用信号量控制多线程程序,Semaphore类是用来创建信号量对象的

使用Semaphore控制多线程

public class UnLockTest {public static String obj1 = "obj1";public static final Semaphore a1 = new Semaphore(1); //设置a1信号量为1public static String obj2 = "obj2";public static final Semaphore a2 = new Semaphore(1);  //设置a2信号量为1public static void main(String[] args) {LockAa la = new LockAa();new Thread(la).start();LockBb lb = new LockBb();new Thread(lb).start();}
}
class LockAa implements Runnable {public void run() {try {System.out.println(new Date().toString() + " LockA 开始执行");while (true) {//tryAcquire(1, TimeUnit.SECONDS) 1秒尝试请求获取线程许可,TimeUnit.SECONDS 获取秒数if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) {System.out.println(new Date().toString() + " LockA 锁住 obj1");//尝试获取a1线程后,尝试获取a2线程if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) {System.out.println(new Date().toString() + " LockA 锁住 obj2");Thread.sleep(60 * 1000); // do something}else{System.out.println(new Date().toString() + "LockA 锁 obj2 失败");}}else{System.out.println(new Date().toString() + "LockA 锁 obj1 失败");}UnLockTest.a1.release(); // 释放a1信号量UnLockTest.a2.release(); //   释放a2信号量Thread.sleep(1000); // 马上进行尝试,现实情况下do something是不确定的}} catch (Exception e) {e.printStackTrace();}}
}
class LockBb implements Runnable {public void run() {try {System.out.println(new Date().toString() + " LockB 开始执行");while (true) {if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) {System.out.println(new Date().toString() + " LockB 锁住 obj2");if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) {System.out.println(new Date().toString() + " LockB 锁住 obj1");Thread.sleep(60 * 1000); // do something}else{System.out.println(new Date().toString() + "LockB 锁 obj1 失败");}}else{System.out.println(new Date().toString() + "LockB 锁 obj2 失败");}UnLockTest.a1.release();UnLockTest.a2.release();Thread.sleep(10 * 1000);}} catch (Exception e) {e.printStackTrace();}}
}

输出结果

Thu Feb 23 02:55:40 CST 2023 LockB 开始执行
Thu Feb 23 02:55:40 CST 2023 LockA 开始执行
Thu Feb 23 02:55:40 CST 2023 LockA 锁住 obj1
Thu Feb 23 02:55:40 CST 2023 LockB 锁住 obj2
Thu Feb 23 02:55:41 CST 2023LockB 锁 obj1 失败
Thu Feb 23 02:55:41 CST 2023LockA 锁 obj2 失败
Thu Feb 23 02:55:42 CST 2023 LockA 锁住 obj1
Thu Feb 23 02:55:42 CST 2023 LockA 锁住 obj2
Thu Feb 23 02:55:51 CST 2023 LockB 锁住 obj2
Thu Feb 23 02:55:51 CST 2023 LockB 锁住 obj1

使用信号量控制多线程锁的步骤
步骤一:创建Semaphore对象

public static String obj1 = "obj1";
public static String obj2 = "obj2";
public static final Semaphore a1 = new Semaphore(1);   //设置1个资源数量
public static final Semaphore a2 = new Semaphore(1);   //设置1个资源数量

步骤二:显式Lock创建

Lock lock1 = new Lock();
Lock lock2 = new Lock();

步骤三:创建线程

new Thread(lock1).start();
new Thread(lock2).start();

步骤四:线程类创建

class ThreadA implements Runnable{public void run() throws Exception{while(true){if(UnLockTest.a1.tryAcquire(1,TimeUnit.SECONDS)){System.out.println(new Date().toString() + " lock1 锁住 obj1");if(UnLockTest.a2.tryAcquire(1,TimeUnit.SECONDS)){System.out.println(new Date().toString() + " lock1 锁住 obj2");Thread.sleep(60*1000);}}else{System.out.println(new Date().toString() + "lock1 锁 obj1 失败");}UnLockTest.a1.release(); // 释放a1信号UnLockTest.a2.release(); //释放a2信号Thread.sleep(1000); // 空出信号量为ThreadB锁对象obj1,obj2    }}
}
class ThreadB implements Runnable{public void run() throws Exception{while(true){if(UnLockTest.a1.tryAcquire(1,TimeUnit.SECONDS)){System.out.println(new Date().toString() + " lock2 锁住 obj1");if(UnLockTest.a2.tryAcquire(1,TimeUnit.SECONDS)){System.out.println(new Date().toString() + " lock2 锁住 obj2");Thread.sleep(60*1000);}}else{System.out.println(new Date().toString() + "lock2 锁 obj1 失败");}UnLockTest.a1.release(); //释放a1信号UnLockTest.a2.release(); //释放a2信号Thread.sleep(1000); // 空出信号量为ThreadA锁对象obj1,obj2    }}
}

输出结果

Thu Feb 23 03:41:41 CST 2023 LockA 开始执行
Thu Feb 23 03:41:41 CST 2023 LockB 开始执行
Thu Feb 23 03:41:41 CST 2023 LockA 锁住 obj1
Thu Feb 23 03:41:41 CST 2023 LockB 锁住 obj2
Thu Feb 23 03:41:42 CST 2023LockB 锁 obj1 失败
Thu Feb 23 03:41:42 CST 2023LockA 锁 obj2 失败
Thu Feb 23 03:41:43 CST 2023 LockA 锁住 obj1
Thu Feb 23 03:41:43 CST 2023 LockA 锁住 obj2
Thu Feb 23 03:41:52 CST 2023 LockB 锁住 obj2
Thu Feb 23 03:41:52 CST 2023 LockB 锁住 obj1

5、获取线程ID
获取线程ID的方式:getId(),自定义编程ID

public class Main extends Object implements Runnable {private ThreadID var;public Main(ThreadID v) {this.var = v;}public void run() {try {print("var getThreadID =" + var.getThreadID());Thread.sleep(2000);print("var getThreadID =" + var.getThreadID());} catch (InterruptedException x) {}}private static void print(String msg) {String name = Thread.currentThread().getName();System.out.println(name + ": " + msg);}public static void main(String[] args) {ThreadID tid = new ThreadID();Main shared = new Main(tid);try {Thread threadA = new Thread(shared, "threadA");threadA.start();Thread.sleep(500);Thread threadB = new Thread(shared, "threadB");threadB.start();Thread.sleep(500);Thread threadC = new Thread(shared, "threadC");threadC.start();} catch (InterruptedException x) {}}
}//继承ThreadLocal类,是本地线程变量
class ThreadID extends ThreadLocal {private int nextID; //线程ID变量public ThreadID() {nextID = 10001; //初始化线程ID}//同步操作线程IDprivate synchronized Integer getNewID() {Integer id = new Integer(nextID);nextID++;return id;}protected Object initialValue() {print("in initialValue()");return getNewID();}public int getThreadID() {Integer id = (Integer) get();return id.intValue();}private static void print(String msg) {String name = Thread.currentThread().getName();System.out.println(name + ": " + msg);}
}

输出结果

threadA: in initialValue()
threadA: var getThreadID =10001
threadB: in initialValue()
threadB: var getThreadID =10002
threadC: in initialValue()
threadC: var getThreadID =10003
threadA: var getThreadID =10001
threadB: var getThreadID =10002
threadC: var getThreadID =10003

6、线程挂起
Thread.join() 进入挂起状态,即等待激活状态

public class SleepingThread extends Thread {private int countDown = 5;private static int threadCount = 0;public SleepingThread() {super("" + ++threadCount);start();}public String toString() {return "#" + getName() + ": " + countDown;}public void run() {while (true) {System.out.println(this);if (--countDown == 0)return;try {sleep(100);}catch (InterruptedException e) {throw new RuntimeException(e);}}}public static void main(String[] args)throws InterruptedException {for (int i = 0; i < 5; i++)new SleepingThread().join();System.out.println("线程已被挂起");}
}

输出结果

#1: 5
#1: 4
#1: 3
#1: 2
#1: 1
#2: 5
#2: 4
#2: 3
#2: 2
#2: 1
#3: 5
#3: 4
#3: 3
#3: 2
#3: 1
#4: 5
#4: 4
#4: 3
#4: 2
#4: 1
#5: 5
#5: 4
#5: 3
#5: 2
#5: 1
线程已被挂起

7、终止进程
interrupt() ##终止进程
isInterrupt() ##判断是否为终止进程

public class MyThread extends Thread {@Overridepublic void run() {try {sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException, InterruptedException {Thread thread = new MyThread();thread.start();System.out.println(new Date());System.out.println("50秒之内按任意键中断线程");System.in.read();thread.interrupt(); //提前终止程序thread.join();  //挂起程序System.out.println("程序已退出");System.out.println(new Date());}
}

输出结果

Thu Feb 23 04:27:01 CST 2023
50秒之内按任意键中断线程程序已退出
Thu Feb 23 04:27:02 CST 2023

8、生产者/消费者问题
需要的是什么?
1、共享存储空间 content

class CubbyHole{private int contents;    //空间存储量private boolean available = false;  //是否可用//获取public synchronized int get(){while(available == false){try{wait();}catch(Exception e){}}available = false;notifyAll();return contents;}public synchronized void put(int value){while(available == true){try{wait();}catch(Exception e){}}contents = values;available = true;notifyAll();}
}

2、生产者线程 producter

class Consumer extends Thread{private CubbyHole cubbyhole;private int number;public Consumer(CubbyHole c,int number){cubbyhole = c;this.number = number;}public void run(){int value = 0;for(int i = 0;i<10;i++){value = cubbyhole.get();System.out.println("消费者 #" + this.number+ " got: " + value);}}
}

3、消费者线程 consumer

public Producer extends Thread{private CubbyHole cubbyhole;private int number;public Producer(CubbyHole c,int number){cubbyhole = c;this.number = number;}public void run(){for(int i = 0; i < 10 ; i++){cubbyhole.put(i);System.out.println("生产者 #" + this.number + " put: " + i);try {sleep((int)(Math.random() * 100));} catch (InterruptedException e) { }}}
}

输出结果

消费者 #1 got: 0
生产者 #1 put: 0
生产者 #1 put: 1
消费者 #1 got: 1
生产者 #1 put: 2
消费者 #1 got: 2
生产者 #1 put: 3
消费者 #1 got: 3
生产者 #1 put: 4
消费者 #1 got: 4
生产者 #1 put: 5
消费者 #1 got: 5
生产者 #1 put: 6
消费者 #1 got: 6
生产者 #1 put: 7
消费者 #1 got: 7
生产者 #1 put: 8
消费者 #1 got: 8
生产者 #1 put: 9
消费者 #1 got: 9

Java实例——线程相关推荐

  1. java设置子线程优先级_Java 实例 - 线程优先级设置

    Java 实例 - 线程优先级设置 以下实例演示了如何通过setPriority() 方法来设置线程的优先级: SimplePriorities.java 文件 public class Simple ...

  2. java 父线程_Java父线程(或是主线程)等待所有子线程退出的实例

    导读热词 实例如下: static void testLock1(){ final AtomicInteger waitCount = new AtomicInteger(30000); final ...

  3. java thread exit方法_实例分析Java终止线程和stop()方法

    Java终止线程实例和stop()方法源码阅读 了解线程 概念 线程 是程序中的执行线程.Java 虚拟机允许应用程序并发地运行多个执行线程. 线程特点 拥有状态,表示线程的状态,同一时刻中,JVM中 ...

  4. Java Daemon线程

    1 所谓守护线程就是运行在程序后台的线程,程序的主线程Main(比方java程序一开始启动时创建的那个线程)不会是守护线程 2.Daemon thread在Java里面的定义是,如果虚拟机中只有Dae ...

  5. Java 守护线程概述

    Java的线程分为两种:User Thread(用户线程).DaemonThread(守护线程). 只要当前JVM实例中尚存任何一个非守护线程没有结束,守护线程就全部工作:只有当最后一个非守护线程结束 ...

  6. JAVA中线程同步的方法(7种)汇总

    JAVA中线程同步的方法(7种)汇总 同步的方法: 一.同步方法 即有synchronized关键字修饰的方法. 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法. ...

  7. Java并发—线程池ThreadPoolExecutor基本总结

    原文作者:Matrix海子 原文地址:Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线 ...

  8. Java守护线程概述

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  9. Thrift入门及Java实例演示

    来源:http://www.micmiu.com/soa/rpc/thrift-sample/ Thrift入门及Java实例演示 作者: Michael日期: 2012 年 6 月 14 日 发表评 ...

最新文章

  1. 代码 删除的stach 找回_阿里大佬教你,如何写好 Java 代码!
  2. Rapid7警告声明:远程桌面协议(RDP)暴露数百万 Windows 终端
  3. python判断对错题_python 初学者错题本
  4. c# imager让图片有圆角unity_Qt编写自定义控件24-图片轮播控件
  5. 数字三角形问题 (动态规划初步)
  6. 使用独立主机时需要关注的问题
  7. 教你玩转CSS 下拉菜单
  8. LeetCode 211. 添加与搜索单词 - 数据结构设计(Trie树)
  9. JavaScript脚本语言介绍并实现第一个Hello World程序
  10. maven 阿里云的镜象
  11. Win10官方原版ISO下载
  12. 74ls175四人抢答器电路图_用数字电路实现四人抢答器
  13. 大数据与云计算之间的关系是怎样的?
  14. MSOCache文件夹能否删除?
  15. C++实验02(02)华氏温度转换为摄氏温度
  16. 工欲善其事,必先利其器-程序员工具推荐
  17. jdk11的class反射机制,将newInstance()方法设置为了不建议使用了,怎么通过反射创建新的对象
  18. 计算机组装与维护试题汇总2013,匡子平2013年上期85《计算机组装与维护》期末试题及答案...
  19. 问题备忘: httpclient连接池异常引发的惨案
  20. 云计算的认识和看法_我的关于云计算的看法和认识

热门文章

  1. long + ulong_ULONG_MAX常数,带C ++示例
  2. c++编程题2——ISBN计算识别码
  3. 详细 | 图神经网络从入门到入门
  4. 跨专业考计算机哪个专业好考吗,考研常识:跨专业考研好考专业?
  5. BUUCTF:LSB
  6. VMware卸载重装心得
  7. matlab两个for循环嵌套加速,使用bsxfun加速Matlab嵌套for循环
  8. 同事写的SpringBoot代码不需要Controller、Service、DAO?只因为用了这个工具
  9. RGB565,RGB555, RGB888,RGB32转换
  10. python连接MySQL数据库的示例代码