【Java基础总结】多线程

 1. 实现多线程的两种方式

 1 //第一种:继承Thread类,重写run()方法
 2 class ThreadTest1 extends Thread{
 3     public void run(){
 4         String threadName = Thread.currentThread().getName();
 5         for(int i=0;i<10;i++){
 6             System.out.println("ThreadTest1 "+threadName+" running ... "+i);
 7         }
 8     }
 9 }
10 
11 //第二种:实现Runnable接口,重写run()方法
12 class ThreadTest2 implements Runnable{
13     public void run(){
14         String threadName = Thread.currentThread().getName();
15         for(int i=0;i<10;i++){
16             System.out.println("ThreadTest2 "+threadName+" running ... "+i);
17         }
18     }
19 }

实现方式不同,使用方式也不同

public class Demo1{    public static void main(String[] args){ThreadTest1 t1 = new ThreadTest1();ThreadTest1 t2 = new ThreadTest1();Thread t3 = new Thread(new ThreadTest2());Thread t4 = new Thread(new ThreadTest2());t1.start();t2.start();t3.start();t4.start();}
}

运行结果大致如下:

ThreadTest1 Thread-0 running ... 0
ThreadTest2 Thread-3 running ... 0
ThreadTest2 Thread-2 running ... 0
ThreadTest1 Thread-1 running ... 0
ThreadTest2 Thread-2 running ... 1
ThreadTest2 Thread-3 running ... 1
ThreadTest1 Thread-0 running ... 1
ThreadTest2 Thread-3 running ... 2
ThreadTest2 Thread-2 running ... 2
ThreadTest1 Thread-1 running ... 1
ThreadTest2 Thread-2 running ... 3
ThreadTest2 Thread-3 running ... 3
ThreadTest1 Thread-0 running ... 2
ThreadTest2 Thread-3 running ... 4
ThreadTest2 Thread-2 running ... 4
ThreadTest1 Thread-1 running ... 2
ThreadTest2 Thread-2 running ... 5
ThreadTest2 Thread-3 running ... 5
ThreadTest1 Thread-0 running ... 3
ThreadTest2 Thread-3 running ... 6
ThreadTest2 Thread-2 running ... 6
ThreadTest1 Thread-1 running ... 3
ThreadTest2 Thread-2 running ... 7
ThreadTest2 Thread-3 running ... 7
ThreadTest2 Thread-3 running ... 8
ThreadTest2 Thread-3 running ... 9
ThreadTest1 Thread-0 running ... 4
ThreadTest1 Thread-0 running ... 5
ThreadTest2 Thread-2 running ... 8
ThreadTest2 Thread-2 running ... 9
ThreadTest1 Thread-1 running ... 4
ThreadTest1 Thread-0 running ... 6
ThreadTest1 Thread-0 running ... 7
ThreadTest1 Thread-0 running ... 8
ThreadTest1 Thread-1 running ... 5
ThreadTest1 Thread-0 running ... 9
ThreadTest1 Thread-1 running ... 6
ThreadTest1 Thread-1 running ... 7
ThreadTest1 Thread-1 running ... 8
ThreadTest1 Thread-1 running ... 9
View Code

 

2. 线程共享资源

建议使用 实现Runnable接口,重写run方法 的方式来实现多线程,它有如下优点:

1. 线程和代码分离,多线程间可以共享资源

2. 避免了单继承带来的局限性

3. 多线程之间可以共享资源

tip

Thread.currentThread().getName()  获得当前线程的名称
threadObj.setName()  设置线程名称

 

案例:售票

class ThreadTest4 implements Runnable{private int ticket=20;public void run(){String threadName = Thread.currentThread().getName();while(ticket>0){System.out.println("ThreadTest4 "+threadName+" 售出 "+ticket+" 号票");ticket--;}}
}

使用情况1:

     (new Thread(new ThreadTest4(), "窗口a")).start();(new Thread(new ThreadTest4(), "窗口b")).start();(new Thread(new ThreadTest4(), "窗口c")).start();(new Thread(new ThreadTest4(), "窗口d")).start();

运行情况说明A、B、C、D四个窗口也没用共享count这个资源

主线程名称:main
ThreadTest4 窗口a 售出 20 号票
ThreadTest4 窗口a 售出 19 号票
ThreadTest4 窗口b 售出 20 号票
ThreadTest4 窗口b 售出 19 号票
ThreadTest4 窗口b 售出 18 号票
ThreadTest4 窗口b 售出 17 号票
ThreadTest4 窗口b 售出 16 号票
ThreadTest4 窗口b 售出 15 号票
ThreadTest4 窗口a 售出 18 号票
ThreadTest4 窗口b 售出 14 号票
ThreadTest4 窗口d 售出 20 号票
ThreadTest4 窗口c 售出 20 号票
ThreadTest4 窗口d 售出 19 号票
ThreadTest4 窗口b 售出 13 号票
ThreadTest4 窗口a 售出 17 号票
ThreadTest4 窗口b 售出 12 号票
ThreadTest4 窗口d 售出 18 号票
ThreadTest4 窗口c 售出 19 号票
ThreadTest4 窗口d 售出 17 号票
ThreadTest4 窗口b 售出 11 号票
ThreadTest4 窗口a 售出 16 号票
ThreadTest4 窗口b 售出 10 号票
ThreadTest4 窗口d 售出 16 号票
ThreadTest4 窗口c 售出 18 号票
ThreadTest4 窗口d 售出 15 号票
ThreadTest4 窗口b 售出 9 号票
ThreadTest4 窗口a 售出 15 号票
ThreadTest4 窗口b 售出 8 号票
ThreadTest4 窗口d 售出 14 号票
ThreadTest4 窗口c 售出 17 号票
ThreadTest4 窗口d 售出 13 号票
ThreadTest4 窗口b 售出 7 号票
ThreadTest4 窗口a 售出 14 号票
ThreadTest4 窗口b 售出 6 号票
ThreadTest4 窗口d 售出 12 号票
ThreadTest4 窗口c 售出 16 号票
ThreadTest4 窗口d 售出 11 号票
ThreadTest4 窗口b 售出 5 号票
ThreadTest4 窗口a 售出 13 号票
ThreadTest4 窗口b 售出 4 号票
ThreadTest4 窗口d 售出 10 号票
ThreadTest4 窗口c 售出 15 号票
ThreadTest4 窗口d 售出 9 号票
ThreadTest4 窗口b 售出 3 号票
ThreadTest4 窗口a 售出 12 号票
ThreadTest4 窗口b 售出 2 号票
ThreadTest4 窗口d 售出 8 号票
ThreadTest4 窗口c 售出 14 号票
ThreadTest4 窗口d 售出 7 号票
ThreadTest4 窗口b 售出 1 号票
ThreadTest4 窗口a 售出 11 号票
ThreadTest4 窗口a 售出 10 号票
ThreadTest4 窗口d 售出 6 号票
ThreadTest4 窗口c 售出 13 号票
ThreadTest4 窗口d 售出 5 号票
ThreadTest4 窗口a 售出 9 号票
ThreadTest4 窗口d 售出 4 号票
ThreadTest4 窗口c 售出 12 号票
ThreadTest4 窗口d 售出 3 号票
ThreadTest4 窗口a 售出 8 号票
ThreadTest4 窗口d 售出 2 号票
ThreadTest4 窗口c 售出 11 号票
ThreadTest4 窗口d 售出 1 号票
ThreadTest4 窗口a 售出 7 号票
ThreadTest4 窗口c 售出 10 号票
ThreadTest4 窗口a 售出 6 号票
ThreadTest4 窗口a 售出 5 号票
ThreadTest4 窗口a 售出 4 号票
ThreadTest4 窗口a 售出 3 号票
ThreadTest4 窗口a 售出 2 号票
ThreadTest4 窗口a 售出 1 号票
ThreadTest4 窗口c 售出 9 号票
ThreadTest4 窗口c 售出 8 号票
ThreadTest4 窗口c 售出 7 号票
ThreadTest4 窗口c 售出 6 号票
ThreadTest4 窗口c 售出 5 号票
ThreadTest4 窗口c 售出 4 号票
ThreadTest4 窗口c 售出 3 号票
ThreadTest4 窗口c 售出 2 号票
ThreadTest4 窗口c 售出 1 号票
View Code

使用情况2:

    ThreadTest4 t2 = new ThreadTest4();(new Thread(t2,"窗口1")).start();(new Thread(t2,"窗口2")).start();(new Thread(t2,"窗口3")).start();(new Thread(t2,"窗口4")).start();

运行情况说明A、B、C、D四个窗口共享count这个资源(但发生了访问冲突)

主线程名称:main
ThreadTest4 窗口1 售出 20 号票
ThreadTest4 窗口2 售出 20 号票
ThreadTest4 窗口2 售出 19 号票
ThreadTest4 窗口2 售出 18 号票
ThreadTest4 窗口2 售出 17 号票
ThreadTest4 窗口2 售出 16 号票
ThreadTest4 窗口2 售出 15 号票
ThreadTest4 窗口2 售出 14 号票
ThreadTest4 窗口2 售出 13 号票
ThreadTest4 窗口2 售出 12 号票
ThreadTest4 窗口2 售出 11 号票
ThreadTest4 窗口2 售出 10 号票
ThreadTest4 窗口2 售出 9 号票
ThreadTest4 窗口2 售出 8 号票
ThreadTest4 窗口2 售出 7 号票
ThreadTest4 窗口3 售出 7 号票
ThreadTest4 窗口1 售出 5 号票
ThreadTest4 窗口2 售出 6 号票
ThreadTest4 窗口1 售出 3 号票
ThreadTest4 窗口4 售出 4 号票
ThreadTest4 窗口3 售出 4 号票
ThreadTest4 窗口1 售出 1 号票
ThreadTest4 窗口2 售出 2 号票
View Code

 

3. 线程同步

   多线程中涉及到共享数据时,会出现线程安全问题。就上面的售票案例来说,若没有加 synchronized 关键字,在多个线程同时使用ticket这个共享数据时,会出现同一个ticket被使用两次这样的看似不可能的情况。另外还有一种情况,事实上ticket这个共享数据是类ThreadTest4对象t2中的变量,所以若是在主线程中添加t2.run();语句的话,也是会发生线程安全问题的。

   在Java里面,同步锁的概念就是这样的。任何一个Object Reference都可以作为同步锁。我们可以把Object Reference理解为对象在内存分配系统中的内存地址。

 1 class ThreadTest5 implements Runnable{
 2     private int ticket=20;
 3     public void run(){
 4         while(ticket>0){        
 5             String threadName = Thread.currentThread().getName();
 6             //同步代码块(越小越好)
 7             synchronized(this){
 8                 if(ticket>0){
 9                     System.out.println(threadName + " sales ticket "+ticket);
10                     ticket--;
11                 }
12             }
13         }
14     }
15 }
16 
17 public class Demo3{
18     public static void main(String[] args){
19         ThreadTest5 t = new ThreadTest5();
20         (new Thread(t, "窗口A")).start();
21         (new Thread(t, "窗口B")).start();
22         (new Thread(t, "窗口C")).start();
23         (new Thread(t, "窗口D")).start();
24     }
25 }

运行结果

窗口A sales ticket 20
窗口A sales ticket 19
窗口A sales ticket 18
窗口A sales ticket 17
窗口A sales ticket 16
窗口A sales ticket 15
窗口A sales ticket 14
窗口A sales ticket 13
窗口A sales ticket 12
窗口A sales ticket 11
窗口A sales ticket 10
窗口D sales ticket 9
窗口D sales ticket 8
窗口D sales ticket 7
窗口D sales ticket 6
窗口D sales ticket 5
窗口D sales ticket 4
窗口D sales ticket 3
窗口C sales ticket 2
窗口B sales ticket 1
View Code

(1)同步代码块

synchronized(类或对象){//需要同步的代码段
}

(2)同步函数

(非static的情况)

public synchronized void fun(){//代码段
}

等价于(调用此同步函数的对象作为此同步函数的同步锁)

public void fun() {synchronized(this) {//代码段
    }
} 

(static的情况)

public static synchronized void fun() {//代码段
}

静态变量或静态方法加载到内存中时,内存中没有本类对象,但一定有了该类对应的字节码文件(类名.class),该对象的类型是class。静态同步函数使用的同步锁是所在类的字节码文件。

 

线程同步的前提:

  1)2个或2个以上的线程

  2)使用同一把锁
保证同步中只有一个线程在运行。

好处:解决线程安全问题
弊端:多个线程需要判断锁,消耗资源

 

4. 线程通信

经典的生产者和消费者问题

假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费。如果仓库中没有产品,则生产者可以将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止。如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止。显然,这是一个同步问题,生产者和消费者共享同一资源,并且,生产者和消费者之间彼此依赖,互为条件向前推进

4.1 synchronized和wait、notify、notifyAll

 wait() 使得当前线程必须要等待,并释放对锁的拥有权,等到另外一个线程调用notify()或者notifyAll()方法

 notify() 会唤醒一个等待当前对象的锁的线程

 notifyAll() 唤醒所有一个等待当前对象的锁的线程

一个小比较
  当线程调用了wait()方法时,它会释放掉对象的锁。
  另一个会导致线程暂停的方法:Thread.sleep(millisecond),它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。

 2     class Repository{
 3         private int count=0;        //当前仓库存放商品数量
 4         private int capacity=5;        //仓库容量
 5         private String goodsName;    //商品名称
 6         public Repository(String goodsName){
 7             this.goodsName = goodsName;
 8         }
 9         public void store(String threadName){
10             synchronized(this){
11                 while(this.count>=this.capacity){
12                     System.out.println("[" + threadName + "]仓库已达到最大容量 " + this.capacity + " 个 !!");
13                     try{this.wait();}
14                     catch(Exception e){}
15                 }
16                 this.count++;
17                 System.out.println("[" + threadName + "]仓库增加了一个"+this.goodsName+",现有"+this.goodsName+"["+this.count+"] 个");
18                 this.notifyAll();
19             }
20         }
21         public void fetch(String threadName){
22             synchronized(this){
23                 while(this.count<1){
24                     System.out.println("[" + threadName + "]仓库没有"+this.goodsName+"!!");
25                     try{
26                         this.wait();
27                     }catch(Exception e){
28                         
29                     }
30                 }
31                 this.count--;
32                 System.out.println("[" + threadName + "]仓库减少了一个"+this.goodsName+",现有"+this.goodsName+"["+this.count+"] 个");
33                 this.notifyAll();
34             }
35         }
36     }
37     //生产者
38     class Producter implements Runnable{
39         private Repository repository ;
40         public Producter(Repository repository){
41             this.repository = repository;
42         }
43         public void run(){
44             String threadName = Thread.currentThread().getName();
45             while(true){
46                 try{ 
47                     //sleep 2秒模拟生产过程
48                     Thread.sleep(1000); 
49                 }catch(Exception e){
50                     
51                 }
52                 //把生产的商品存放到仓库
53                 repository.store(threadName);
54             }
55         }
56     }
57     //消费者
58     class Consumer implements Runnable{
59         private Repository repository ;
60         public Consumer(Repository repository){
61             this.repository = repository;
62         }
63         public void run(){
64             String threadName = Thread.currentThread().getName();
65             while(true){
66                 //将商品从仓库取出来
67                 repository.fetch(threadName);
68                 try{ 
69                     //sleep 4秒模拟消费过程
70                     Thread.sleep(2000); 
71                 }catch(Exception e){
72                     
73                 }
74             }    
75         }
76     }
77     public class Thread06{
78         public static void main(String[] args){
79             Repository repository = new Repository("馒头");
80             
81             Producter pro1 = new Producter(repository);
82             Consumer con1 = new Consumer(repository);
83             //生产者和消费者各2个
84             (new Thread(pro1, "生产者A")).start();    
85             (new Thread(pro1, "生产者B")).start();
86             (new Thread(con1, "消费者1")).start();
87             (new Thread(con1, "消费者2")).start();
88         }
89     }

其中一种运行结果:

 1 [消费者1]仓库没有馒头!!
 2 [消费者2]仓库没有馒头!!
 3 [生产者A]仓库增加了一个馒头,现有馒头[1] 个
 4 [消费者2]仓库减少了一个馒头,现有馒头[0] 个
 5 [消费者1]仓库没有馒头!!
 6 [生产者B]仓库增加了一个馒头,现有馒头[1] 个
 7 [消费者1]仓库减少了一个馒头,现有馒头[0] 个
 8 [生产者A]仓库增加了一个馒头,现有馒头[1] 个
 9 [生产者B]仓库增加了一个馒头,现有馒头[2] 个
10 [生产者A]仓库增加了一个馒头,现有馒头[3] 个
11 [消费者2]仓库减少了一个馒头,现有馒头[2] 个
12 [生产者B]仓库增加了一个馒头,现有馒头[3] 个
13 [消费者1]仓库减少了一个馒头,现有馒头[2] 个
14 [生产者A]仓库增加了一个馒头,现有馒头[3] 个
15 [生产者B]仓库增加了一个馒头,现有馒头[4] 个
16 [消费者2]仓库减少了一个馒头,现有馒头[3] 个
17 [生产者A]仓库增加了一个馒头,现有馒头[4] 个
18 [消费者1]仓库减少了一个馒头,现有馒头[3] 个
19 [生产者B]仓库增加了一个馒头,现有馒头[4] 个
20 [生产者A]仓库增加了一个馒头,现有馒头[5] 个
21 [生产者B]仓库已达到最大容量 5 个 !!
22 [消费者2]仓库减少了一个馒头,现有馒头[4] 个
23 [生产者B]仓库增加了一个馒头,现有馒头[5] 个
24 [生产者A]仓库已达到最大容量 5 个 !!
25 [消费者1]仓库减少了一个馒头,现有馒头[4] 个
26 [生产者A]仓库增加了一个馒头,现有馒头[5] 个
27 [生产者B]仓库已达到最大容量 5 个 !!
28 [生产者A]仓库已达到最大容量 5 个 !!

(运行结果分析)

1)线程“消费者1”调用repositoy.fetch()方法去仓库取馒头。进入synchronized块,刚一执行while语句,结果 this.count<1 为真,直接就wait()进入等待队列,最后释放了锁
(就绪队列[消费者2,生产者A,生产者B],等待队列[消费者1]2)线程“消费者2”同“消费者1”的遭遇是相同的(对此,我们深表同情)
(就绪队列[生产者A,生产者B], 等待队列[消费者1,消费者2]3)线程“生产者A”生产完商品后,调用repository.store()方法把商品存到了仓库中。在store方法里,使用notifyAll方法唤醒了所有在沉睡wait的线程,最后释放了锁
(就绪队列[生产者A,生产者B,消费者1,消费者2],等待队列[]4)线程“消费者2”从上次wait的地方开始执行(从哪里跌倒,就从哪里爬起来)。同样是while语句,但这次 this.count<1 不为真了,于是乎顺利脱坑,接着执行 this.count--,把仓库仅有的一个馒头给拿走了,走之前还不忘大喊一句“仓库减少了一个馒头,现有馒头[0] 个”。同样是notifyAll方法唤醒所有沉睡wait的线程,释放锁
(就绪队列[生产者A,生产者B,消费者1,消费者2],等待队列[]5)线程“消费者1”辛辛苦苦抢到了锁,终于能执行syschronized块代码了。和“消费者2”一样,也是从上次wait的地方接着执行,也是while语句,但不同的是 this.count<1 为真,线程“生产者A”生产存放到仓库的仅有的一个馒头被“消费者2”给吃了,可以想象此时的“消费者1”心里是万念俱灰的。啥也别说了,接着沉睡wait吧。(释放了锁)
(就绪队列[生产者A,生产者B,消费者2],等待队列[消费者1])

**** 在接下来的几十个回合中,时而生产者线程夺得仓库锁,称霸武林,时而消费者线程夺得,笑傲江湖,仓库商品也是时增时减,但总体上还是生产者线程抢到的次数多,因为生产者够快,当消费者还在花2秒钟费劲的消化时,生产者早就1秒生产完毕,参与仓库锁的再次争夺了,可见“天下武功,唯快不破” *****“仓库里没有馒头为什么不通知我?”,线程“消费者2”不满“消费者1”对仓库情况的隐瞒不报,“你要是早告诉我,我也就不用争抢仓库锁,抢到了也没用,里面根本就没有馒头,去了也是wait”。(第1、2步) “你还有脸说我,你把生产者A生产存放在仓库仅有的一个馒头吃了,你明知道仓库再也没有馒头了,也不告诉我,还让我傻了吧唧抢到仓库锁,去了也白搭”。“消费者1”反驳道,它同样也很委屈。(第4、5步) “管我什么事,抢仓库锁的有不只你一个,我也去抢了,白费了劲,还没抢到
....”,线程“消费者2”道。“要是仓库没有馒头的时侯,只唤醒那帮生产者就好了”,线程“消费者1”和“消费者2”异口同声的说道。

处理线程通信必须遵循一种原则:对于生产者,在生产者没有生产之前,要通知消费者等待;在生产者生产之后,马上又通知消费者消费;对于消费者,在消费者消费之后,要通知生产者已经消费结束,需要继续生产新的产品以供消费。

4.2 Lock和Condition

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。

Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用

 

5. 停止线程的方法

interrupt()        //停止线程
isInterrupt()     //判断线程是否停止

6. 守护线程和join方法

  守护线程是为其他线程提供便利服务的,当全部的用户线程结束后,守护线程才会随JVM结束工作。 thread.setDaemon(true); 

public static void main(String[] args){    Thread t3 = new Thread(test2, "线程t3");t3.start();t3.join();  //主线程就此陷入等待,直到t3线程结束。
}

7. 线程优先级和yield方法

线程的优先级从低到高:1-10,优先级高的的优先执行,每个新线程都继承了父线程的优先级,常量:Thread.MIN_PRIORITY 值为1,Thread.MAX_PRIORITY 值为10,Thread.NORM_PRIORITY 值为5

void setPriority(priority)    //设置线程优先级
int getPriority()            //获取线程优先级

 yield() 线程从执行状态变成就绪状态。

 

转载于:https://www.cnblogs.com/lhat/p/6819170.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/400378.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【51单片机快速入门指南】5:软件SPI

目录硬知识SPI协议简介SPI接口介绍SPI接口连接图SPI数据传输方向SPI传输模式软件SPI程序源码Soft_SPI.cSoft_SPI.h普中51-单核-A2 STC89C52 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 上位机&#xff1a;Vofa 1.3.10 源于软件模拟SPI接口程序代码&…

svn搭建本地服务端

使用VisualSVN Server来完成,下载地址:https://www.visualsvn.com/server/download/ 我安装的版本是3.3.1,安装的时候选择了标准版本&#xff0c;另外一个版本需要付费(日志跟踪、VDFS等功能)更多可以参考https://www.visualsvn.com/server/licensing/安装完成之后&#xff0c;…

【51单片机快速入门指南】5.1:SPI与DS1302时钟芯片

目录硬知识DS1302 简介DS1302 使用控制寄存器日历/时钟寄存器DS1302 的读写时序电路设计示例程序DS1302.cDS1302.h测试程序main.c实验现象普中51-单核-A2 STC89C52 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 硬知识 摘自《普中 51 单片机开发攻略》…

【格局视野】三色需求与工作层次

三色需求 人们的社会经济生活本身就是一个互相交换&#xff0c;价值传递的循环&#xff0c;但这个循环有一个核心&#xff0c;这个核心就是社会大众的需求&#xff0c;也可以称为市场需求&#xff0c;围绕这个需求产生了层级递进的需求关系。 第一个层次是蓝色需求 是最基础的社…

关于linux-Centos 7下mysql 5.7.9的rpm包的安装方式

环境介绍>>>>>>>>>>>>>>>>>> 操作系统&#xff1a;Centos 7.1 mysql数据库版本&#xff1a;mysql5.7.9 mysql官方网站&#xff1a;http://www.mysql.com 原文地址&#xff1a;http://www.cnblogs.com/5201351/p/4912614…

【51单片机快速入门指南】5.2:SPI读取 12位ADC XPT2046 芯片

目录硬知识ADC 简介分辨率转换误差转换速率ADC 转换原理逐次逼近型 ADC双积分型 ADCXPT2046 芯片介绍参考电压内部参考电压外部参考电压输入工作模式单端工作模式差分工作模式温度测量电池电压测量压力测量数字接口笔中断输出转换周期16 时钟周期转换数字时序15 时钟周期转换数…

flask中 app.run(host='0.0.0.0', port=5000, debug=False) 不能用外网ip访问的解决办法

pycharm 2018开启debug模式和修改host&#xff1a; 在Pycharm 2018中&#xff0c;如果想要开启debug模式和更改端口号&#xff0c;则需要编辑项目配置。直接在app.run中更改是无效的。示例图如下&#xff1a; 将 app.run() 改成 app.run(debugFalse) 保存文件&#xff0c…

开发第一个spring boot应用

为什么80%的码农都做不了架构师&#xff1f;>>> 我们来用spring boot开发一个简单的“hello world”web应用&#xff0c;使用maven构建。开始之前&#xff0c;先检查你的java与maven的版本&#xff0c;看是否是spring boot1.3支持的版本&#xff1a; $ java -versi…

机器学习中规则化和模型选择知识

1 问题 模型选择问题&#xff1a;对于一个学习问题&#xff0c;可以有多种模型选择。比如要拟合一组样本点&#xff0c;可以使用线性回归&#xff0c;也可以用多项式回归。那么使用哪种模型好呢&#xff08;能够在偏差和方差之间达到平衡最优&#xff09;&#xff1f; 还有一类…

【51单片机快速入门指南】5.3:SPI控制晶联讯JLX12864G_08602 LCD屏幕

目录示例程序JLX12864G_08602.cJLX12864G_08602.hJLX12864G_08602_Font.cJLX12864G_08602_Font.h测试程序main.c效果STC12LE5A60S2 12MHz Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 示例程序 stdint.h见【51单片机快速入门指南】1&#xff1a;基础知…

Android二维码之创建

由于微信的推出二维码走进了我们的生活&#xff0c;并且越来越多的人们正在发挥着自己的想象力去使用它&#xff0c;来方便我们的生活&#xff0c;我曾经听说过一个笑话&#xff0c;当我们死后&#xff0c;墓碑上不再有墓志铭&#xff0c;而会出现一个记录你一生信息的二维码&a…

如何开展软件架构之概念架构

如何开展软件架构之概念架构 到目前为止&#xff0c;我们已经完成了需求的分析过程&#xff0c;总结来说&#xff0c;主要的步聚是 一&#xff09;需求结构化&#xff0c; 二&#xff09;分析约束影响 三&#xff09;重点关注质量需求。 那么接下来的阶段则是系统的概念架构了&…

【51单片机快速入门指南】6.1:LCD1602的八线、四线控制及自定义符号,完美兼容Proteus仿真

目录硬知识显示特性接口定义操作时序写操作时序读操作时序寄存器忙标志位BF地址计数器&#xff08;AC&#xff09;显示数据寄存器&#xff08;DDRAM&#xff09;CGROMCGRAM指令清屏指令光标归位指令进入模式设置指令显示开关控制指令设定显示屏或光标移动方向指令功能设定指令设…

在MAC OS 下配置python + Flask ,并支持pyCharm编辑器

https://www.cnblogs.com/lgphp/p/3841098.html 在MAC OS 下配置python Flask ,并支持pyCharm编辑器 flask是一个micro framework &#xff0c;伸缩性很强。可以部署到openshift 的PAAS里。这个框架上手非常快。喜欢的可以试试。 若实在MAC里&#xff0c;python已经默认安装了…

MySql简介及概念

关系型数据库系统&#xff1a;建立在关系模型上的数据库系统。 关系模型:当将日常生活中的实体&#xff08;学生&#xff09;&#xff0c;和实体的属性&#xff08;学生的学号&#xff0c;姓名&#xff09;保存数据中时&#xff0c;该如何处理该实体结构。1、数据结构可以规定&…

【51单片机快速入门指南】6.2:SPI 、八线、四线控制 LCD12864 屏幕及Proteus的仿真(支持中文汉字)

目录硬知识LCD12864简介主控芯片ST7920的功能是&#xff1a;驱动芯片ST7921的功能是&#xff1a;引脚功能时序并行通信串行通信指令存储结构操作取模软件的配置示例程序st7920.cst7920.h测试程序显示图片图片1实验现象图片2实验现象显示字符英文实验现象中文实验现象Proteus的仿…

【51单片机快速入门指南】仿真实例:幅值可调、频率可调的函数发生器(方波、三角波、正弦波)(1~10kHz)

目录效果设计思路STC89C52 Windows 10 20H2 Proteus 8 Frofessional v8.9 SP2 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 51函数发生器&#xff0c;附工程源码和Proteus仿真文件 效果 0 ~ 5V &#xff0c;50Hz的正弦波&#xff1a; 1 ~ 4V&…

VisualSvn Server介绍

1 、VisualSvn Server VisualSvn Server是免费的&#xff0c;而VisualSvn是收费的。VisualSvn是Svn的客户端&#xff0c;和Visual Studio集成在一起&#xff0c;但是不免费&#xff0c;使用AnkhSvn&#xff08;VS2008插件&#xff09;来代替VisualSvn。使用 VisualSvn Server是…

【51单片机快速入门指南】6.3:DS18B20 单总线数字温度计的多路读取

目录硬知识DS18B20介绍时序初始化时序写时序读时序命令ROM 操作命令ROM 搜索举例存贮器操作命令示例程序DS18B20.cDS18B20.h测试程序定时器中断服务函数单传感器时ID的获取 main.c单传感器读取温度和读取特定ID传感器的温度多路传感器读取普中51-单核-A2 STC89C52 Keil uVisio…

SQL多行转多列

--★转换结果如上图 1、首先创建表&#xff1a; CREATE TABLE [成绩表]( [编号] [int]IDENTITY(1,1) NOT NULL, [姓名] [varchar](50)NULL, [语文] [numeric](5, 2)NULL, [数学] [numeric](5, 2)NULL, [英语] [numeric](5, 2)NULL ) ON [PRIMARY] 2、插入测试数据 INSERT INTO …