0

0

Java多线程详解

PHP中文网

PHP中文网

发布时间:2018-05-15 10:38:57

|

2743人浏览过

|

来源于php中文网

原创

多线程背景知识介绍

利用多线程可以简化模型,编写功能强大的代码,但是要写好多线程却不容易,需要一个长期实践的过程。 

多线程基础概念介绍

进程与线程

①  进程:程序(任务)的执行过程。动态性

持有资源(共享内存,共享文件)和线程。载体

例子:Eclipse、QQ

立即学习Java免费学习笔记(深入)”;

②  线程:

Eclipse:源代码文本编辑、源代码编译、语法校验。

QQ:文字聊天、收发文件。

如果把进程比作成一个班级,那么这个班级中的每一个学生就是线程。学生是班级当中的最小单元,构成班级当中的最小单位。一个班级可以有多个学生,这些学生都使用班级当中共同的桌椅、黑板、粉笔。

线程是系统中最小的执行单元,同一个进程中有多个线程,线程共享进程的资源。

线程的交互

互斥、同步。

Java线程初体验

Java.lang

class Thread

interface Runnable

public void run()

线程的常用方法

类别

方法签名

简介

线程的创建

Thread()

 

Thread(String name)

 

Thread(Runnable target)

 

Thread(Runnable target,String name)

 

线程的方法

void start()

启动线程

static void sleep(long millis)

线程休眠

static void sleep(long millis,int nanos)

void join()

使其他线程等待当前线程终止

void join(long millis)

void join(long millis,int nanos)

static void yield()

当前运行线程释放处理器资源

获取线程引用

static Thread currentThread()

返回当前运行的线程引用

两条线程不做任何处理的时候,会交替运行。

当使用boolean类型控制线程的循环时,要在变量前加上volatile关键字,volatile保证了线程可以正确的读取其他线程写入的值。

注意点:

sleep()方法的作用:使线程休眠指定的时间。

join()方法的作用: //使其他线程等待当前线程执行完毕。

多线程案例

例1:

1 package com.czgo;  
2   
3    
4   
5 /**  
6   
7  * 线程先生  
8   
9  * @author 疯子 
10  
11  * 
12  
13  */ 
14  
15 public class Actor extends Thread { 
16  
17     @Override 
18  
19     public void run() { 
20  
21         //getName():获取当前线程的名称 
22  
23         System.out.println(getName()+"是一个演员!"); 
24  
25         //用来记录线程跑的次数 
26  
27         int count = 0; 
28  
29         boolean keepRunning = true; 
30  
31         while(keepRunning){ 
32  
33             System.out.println(getName()+"登台演出"+(++count)); 
34  
35             if(count==100){ 
36  
37                 keepRunning = false; 
38  
39             } 
40  
41             if(count%10==0){ 
42  
43                 try { 
44  
45                     Thread.sleep(1000); 
46  
47                 } catch (InterruptedException e) { 
48  
49                     e.printStackTrace(); 
50  
51                 } 
52  
53             } 
54  
55         } 
56  
57         System.out.println(getName()+"的演出结束了!"); 
58  
59     } 
60  
61     
62  
63     public static void main(String[] args) { 
64  
65         Thread actor = new Actor(); 
66  
67         //setName:设置线程的名称 
68  
69         actor.setName("Mr.Thread"); 
70  
71         //启动线程 
72  
73         actor.start(); 
74  
75         
76  
77         Thread actressThread = new Thread(new Actress(),"Ms.Runnable"); 
78  
79         actressThread.start(); 
80  
81     } 
82  
83 } 
84  
85   
86  
87 class Actress implements Runnable{ 
88  
89     @Override 
90  
91     public void run() { 
92  
93         //getName():获取当前线程的名称 
94  
95         //currentThread()获取当前线程的引用 
96  
97         System.out.println(Thread.currentThread().getName()+"是一个演员!"); 
98  
99         //用来记录线程跑的次数
100 
101         int count = 0;
102 
103         boolean keepRunning = true;
104 
105         while(keepRunning){
106 
107             System.out.println(Thread.currentThread().getName()+"登台演出"+(++count));
108 
109             if(count==100){
110 
111                 keepRunning = false;
112 
113             }
114 
115             if(count%10==0){
116 
117                 try {
118 
119                     Thread.sleep(1000);
120 
121                 } catch (InterruptedException e) {
122 
123                     e.printStackTrace();
124124 
125                 }
126 
127             }
128 
129         }
130 
131         System.out.println(Thread.currentThread().getName()+"的演出结束了!");   
132 
133     }134 135 }

例2:

军队:

 1 package com.czgo; 
 2  
 3   
 4  
 5 /** 
 6  
 7  * 军队线程 
 8  
 9  * 模拟作战双方的行为
 10 
 11  * @author 疯子
 12 
 13  *
 14 
 15  */
 16 
 17 public class ArmyRunnable implements Runnable {
 18 
 19    
 20 
 21     //volatile保证了线程可以正确的读取其他线程写入的值
 22 
 23     //可见性 ref JMM,happens-before
 24 
 25     volatile boolean keepRunning = true;
 26 
 27    
 28 
 29     @Override
 30 
 31     public void run() {
 32 
 33        
 34 
 35         while(keepRunning){
 36 
 37             //发动5连击
 38 
 39             for(int i=0;i<5;i++){
 40 
 41                 System.out.println(Thread.currentThread().getName()+"进攻对方["+i+"]");
 42 
 43                 //让出了处理器时间,下次谁进攻还不一定呢!
 44 
 45                 Thread.yield();
 46 
 47             }
 48 
 49         }
 50 
 51        
 52 
 53         System.out.println(Thread.currentThread().getName()+"结束了战斗!");
 54 
 55        
 56 
 57     }
 58 
 59 }

关键人物:

1 package com.czgo; 
2  
3   
4  
5 /** 
6  
7  * 关键人物 
8  
9  * @author 疯子
10 
11  *
12 
13  */
14 
15 public class KeyPersonThread extends Thread {
16 
17     @Override
18 
19     public void run() {
20 
21         System.out.println(Thread.currentThread().getName()+"开始了战斗!"); 
22 
23         for(int i=0;i<10;i++){
24 
25             System.out.println(Thread.currentThread().getName()+"左突右杀,攻击随军...");
26 
27         }
28 
29         System.out.println(Thread.currentThread().getName()+"结束了战斗!");
30 
31  
32 
33     }
34 
35 }

舞台:

  1 package com.czgo;  
  2   
  3    
  4   
  5 /**  
  6   
  7  * 隋唐演义大戏舞台  
  8   
  9  * @author win7 
  10  
  11  * 
  12  
  13  */ 
  14  
  15 public class Stage extends Thread { 
  16  
  17     
  18  
  19     @Override 
  20  
  21     public void run() { 
  22  
  23         System.out.println("欢迎观看隋唐演义"); 
  24  
  25         
  26  
  27         try { 
  28  
  29             Thread.sleep(5000); 
  30  
  31         } catch (InterruptedException e2) { 
  32  
  33             e2.printStackTrace(); 
  34  
  35         } 
  36  
  37         
  38  
  39         System.out.println("大幕徐徐拉开"); 
  40  
  41         
  42  
  43         try { 
  44  
  45             Thread.sleep(5000); 
  46  
  47         } catch (InterruptedException e2) { 
  48  
  49             e2.printStackTrace(); 
  50  
  51         } 
  52 
  53         
  54  
  55         System.out.println("话说隋朝末年,隋军与农民起义军杀得昏天暗地..."); 
  56  
  57         
  58  
  59         //隋朝军队 
  60  
  61         ArmyRunnable armyTaskOfSuiDynasty = new ArmyRunnable(); 
  62 
  63         //农民起义军 
  64  
  65         ArmyRunnable armyTaskOfRevolt = new ArmyRunnable(); 
  66  
  67         
  68  
  69         //使用Runnable接口创建线程 
  70  
  71         Thread armyOfSuiDynasty = new Thread(armyTaskOfSuiDynasty,"隋军"); 
  72  
  73         Thread armyOfSuiRevolt = new Thread(armyTaskOfRevolt,"农民起义军"); 
  74  
  75         
  76  
  77         //启动线程,让军队开始作战 
  78  
  79         armyOfSuiDynasty.start(); 
  80  
  81         armyOfSuiRevolt.start(); 
  82  
  83         
  84  
  85         //舞台线程休眠,大家专心观看军队的厮杀 
  86  
  87         try { 
  88  
  89             //Thread会指向当前类的线程 
  90 
  91             Thread.sleep(50); 
  92  
  93         } catch (InterruptedException e) { 
  94  
  95             e.printStackTrace(); 
  96  
  97         } 
  98
  99         System.out.println("正当双方激战正酣,半路杀出了个程咬金");
  100 
  101        
  102 
  103         Thread mrCheng = new KeyPersonThread();
  104 
  105         mrCheng.setName("程咬金");
  106 
  107        
  108 
  109         System.out.println("程咬金的理想就是结束战争,使百姓安居乐业!");
  110 
  111        
  112 
  113         //停止军队作战
  114 
  115         //停止线程的方法
  116 
  117         armyTaskOfSuiDynasty.keepRunning=false;
  118 
  119         armyTaskOfRevolt.keepRunning=false;
  120 
  121       
  122 
  123         try {
  124124 
  125             Thread.sleep(2000);
  126 
  127         } catch (InterruptedException e1) {
  128 
  129             e1.printStackTrace();
  130 
  131         }
  132 
  133        134 135         //历史大戏留给关键人物
  136 
  137         mrCheng.start();
  138 
  139        
  140 
  141         try {
  142 
  143             //使其他线程等待当前线程执行完毕
  144 
  145             mrCheng.join();
  146 
  147         } catch (InterruptedException e) {
  148 
  149             e.printStackTrace();150 151         }
  152 
  153        
  154 
  155         System.out.println("战争结束,人民安居乐业,程先生实现了积极的人生梦想,为人民作出了贡献!");
  156 
  157         System.out.println("谢谢观看隋唐演义,再见!");
  158 
  159     }
  160 
  161    
  162 
  163     public static void main(String[] args) {
  164 
  165         new Stage().start();
  166 
  167     }
  168 
  169 }

线程的正确停止

如何正确的停止Java中的线程:

可以通过boolean类型来控制循环的退出。

not stop方法

stop()方法会让线程戛然而止。

stop()方法停止线程是错误的方法。

线程的交互

争用条件Race Condition

当多个线程同时共享访问同一数据(内存区域)时,每个线程都尝试操作该数据,从而导致数据被破坏(corrupted),这种现象称为争用条件。

什么是互斥?

互斥是怎么实现的?

只能被一个线程所访问,互斥。

互斥的实现:synchronized(intrinsic lock)加锁。

同步的实现:wait()/notify()/notifyAll()。

如何扩展Java并发的知识

Java Memory Mode

         JMM描述了Java线程如何通过内存进行交互

         Happens-before

         Synchronized,volatile&final

Locks&Condition

         Java锁机制和等待条件的高层实现

         Java.util.concurrent.locks

线程安全性

         原子性与可见性

         Java.util.concurrent.atomic

         Synchronized&volatile

         DeadLocks

多线程编程常用的交互模型

         Producer-Consumer模型

         Read-Write Lock模型

         Future模型

         Worker Thread模型

Java5中并发编程工具

         Java.util.concurrent

         线程池ExecutorService

         Callable&Future

         BlockingQueue

推荐两本书:

Core Java

Java concurrency in practice

线程创建的两种方式比较

Thread:

①  继承Thread类;

Runnable:

①  Runnable方式可以避免Thread方式由于Java单继承特性带来的缺陷。

②  Runnable的代码可以被多个线程(Thread实例)共享,适合于多个线程处理同一资源的情况。

案例:

Thread:

 1 package com.czgo; 
 2  
 3   
 4  
 5 class MyThread extends Thread{ 
 6  
 7     
 8  
 9     private int ticketsCont = 5;    //一共有5张火车票
 10 
 11    
 12 
 13     private String name;            //窗口,也即是线程的名字
 14 
 15    
 16 
 17     public MyThread(String name){
 18 
 19         this.name = name;
 20 
 21     }
 22 
 23    24 25     @Override
 26 
 27     public void run() {
 28 
 29        30 31         while(ticketsCont>0){
 32 
 33             ticketsCont--;      //如果还有票,就卖掉一张
 34 
 35             System.out.println(name+"卖了1张票,剩余票数为:"+ticketsCont);
 36 
 37         }
 38 
 39     }
 40 
 41    
 42 
 43 }
 44 
 45  
 46 
 47 public class TicketsThread {
 48 
 49  
 50 
 51     public static void main(String[] args) {
 52 
 53         //创建3个线程,模拟三个窗口卖票
 54 
 55         MyThread mt1 = new MyThread("窗口1");
 56 
 57         MyThread mt2 = new MyThread("窗口2");
 58 
 59         MyThread mt3 = new MyThread("窗口3");
 60 
 61        62 63         //启动这三个线程,也即是窗口,开始卖票
 64 
 65         mt1.start();
 66 
 67         mt2.start();
 68 
 69         mt3.start();
 70 
 71        
 72 
 73     }
 74 
 75  
 76 
 77 }

Runnable:

 1 package com.czgo; 
 2  
 3   
 4  
 5 class MyThread implements Runnable{ 
 6  
 7     
 8  
 9     private int ticketsCont = 5;    //一共有5张火车票
 10 
 11  
 12 
 13     @Override
 14 
 15     public void run() {
 16 
 17        
 18 
 19         while(ticketsCont>0){
 20 
 21             ticketsCont--;      //如果还有票,就卖掉一张
 22 
 23             System.out.println(Thread.currentThread().getName()+"卖了1张票,剩余票数为:"+ticketsCont);
 24 
 25         }
 26 
 27        
 28 
 29     }
 30 
 31    
 32 
 33 }
 34 
 35  
 36 
 37 public class TicketsRunnable {
 38 
 39  
 40 
 41     public static void main(String[] args) {
 42 
 43        
 44 
 45         MyThread mt1 = new MyThread();
 46 
 47         MyThread mt2 = new MyThread();
 48 
 49         MyThread mt3 = new MyThread();
 50 
 51        
 52 
 53         //创建三个线程来模拟三个售票窗口
 54 
 55         Thread th1 = new Thread(mt1,"窗口1");
 56 
 57         Thread th2 = new Thread(mt2,"窗口2");
 58 
 59         Thread th3 = new Thread(mt3,"窗口3");
 60 
 61        
 62 
 63         //启动这三个线程,也即是三个窗口开始卖票
 64 
 65         th1.start();
 66 
 67         th2.start();
 68 
 69         th3.start();
 70 
 71  
 72 
 73     }
 74 
 75  
 76 
 77 }

线程的生命周期

图示:

 

BJXSHOP网上购物系统 - 书店版
BJXSHOP网上购物系统 - 书店版

BJXSHOP购物管理系统是一个功能完善、展示信息丰富的电子商店销售平台;针对企业与个人的网上销售系统;开放式远程商店管理;完善的订单管理、销售统计、结算系统;强力搜索引擎支持;提供网上多种在线支付方式解决方案;强大的技术应用能力和网络安全系统 BJXSHOP网上购物系统 - 书店版,它具备其他通用购物系统不同的功能,有针对图书销售而进行开发的一个电子商店销售平台,如图书ISBN,图书目录

下载

创建:新建一个线程对象,如Thread thd = new Thread()。

就绪:创建了线程对象后,调用了线程的start()方法(注意:此时线程只是进入了线程队列,等待获取cpu服务,具备了运行的条件,但并不一定已经开始运行了)。

运行:处于就绪状态的线程,一旦获取了CPU资源,便进入到运行状态,开始执行run()方法里面的逻辑。

终止:线程的run()方法执行完毕,或者线程调用了stop()方法,线程便进入终止状态。

阻塞:一个正在执行的线程在某些情况下,由于某种原因而暂时让出了CPU资源,暂停了自己的执行,便进入了阻塞状态,如调用了sleep()方法。

 

线程的守护神-守护线程

Java线程有两类:

用户线程:运行在前台,执行具体的任务。

例如程序的主线程、连接网络的子线程等都是用户线程。

 

守护线程:运行在后台,为其他前台线程服务。

特点:一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作。

应用:数据库连接池中的监测线程、JVM虚拟机启动后的监测线程。

最常见的守护线程:垃圾回收线程。

如何设置守护线程

可以通过调用Thread类的setDaemon(true)方法来设置当前线程为守护线程。

注意事项:

setDaemon(true)必须在start()方法之前调用,否则会抛出IllegalThreadStateException异常。

在守护线程中产生的新线程也是守护线程

不是所有的任务都可以分配给守护线程来执行,比如读写操作或者计算逻辑。

案例:

  1 package com.czgo;  
  2   
  3    
  4   
  5 import java.io.File;  
  6   
  7 import java.io.FileOutputStream;  
  8   
  9 import java.io.IOException; 
  10  
  11 import java.io.OutputStream; 
  12  
  13 import java.util.Scanner; 
  14  
  15   
  16  
  17 class DaemonThread implements Runnable{ 
  18  
  19     @Override 
  20  
  21     public void run() { 
  22  
  23         System.out.println("进入守护线程"+Thread.currentThread().getName()); 
  24  
  25         try { 
  26  
  27             writeToFile(); 
  28  
  29         } catch (IOException e) { 
  30  
  31             e.printStackTrace(); 
  32  
  33         } catch (InterruptedException e) { 34  35             e.printStackTrace(); 
  36  
  37         } 
  38  
  39         System.out.println("退出守护线程"+Thread.currentThread().getName()); 
  40  
  41         
  42  
  43     } 
  44  
  45     
  46  
  47     private void writeToFile() throws IOException, InterruptedException{ 
  48  
  49         File filename = new File("C:\\ide"+File.separator+"daemon.txt"); 
  50  
  51         OutputStream os = new FileOutputStream(filename,true); 
  52  
  53         int count = 0; 
  54  
  55         while(count<999){ 
  56  
  57             os.write(("\r\nword"+count).getBytes()); 
  58  
  59             System.out.println("守护线程"+Thread.currentThread().getName()+"向文件中写入了word"+count++); 
  60 
  61             Thread.sleep(1000); 
  62  
  63         } 
  64  
  65         os.close(); 
  66  
  67     } 
  68  
  69 } 
  70  
  71   
  72  
  73 public class DaemonThreadDemo { 
  74  
  75   
  76  
  77     public static void main(String[] args) { 
  78  
  79         
  80  
  81         System.out.println("进入主线程"+Thread.currentThread().getName()); 
  82  
  83         DaemonThread daemonThread = new DaemonThread(); 
  84  
  85         Thread thread = new Thread(daemonThread); 
  86  
  87         thread.setDaemon(true); 
  88  
  89         thread.start(); 
  90  
  91         
  92  
  93         Scanner sc = new Scanner(System.in); 
  94  
  95         sc.next();
  96  
  97         
  98  
  99         System.out.println("退出主线程"+Thread.currentThread().getName());
  100 
  101     }
  102 
  103  
  104 
  105 }

使用jstack生成线程快照

jstack

作用:生成jvm当前时刻线程的快照(threaddump,即当前进程中所有线程的信息)

目的:帮助定位程序问题出现的原因,如长时间停顿、cpu占用率过高等。

如何使用jstack

jstack –l pid

 

内存可见性

可见性介绍

可见性:一个线程对共享变量值的修改,能够及时地被其他线程看到。

共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。

Java内存模型(JMM)

Java内存模型(Java Memory Model)描述了程序中各种变量(线程共享变量)的访问规则,以及在Java中将变量存储到内存和从内存中读取出变量这样的底层细节。

所有变量都存储在主内存中

每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝)。

 

线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读写。

不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成。

共享变量可见性实现的原理

线程1对共享变量的修改要想被线程2及时看到,必须要经过如下2个步骤:

把工作内存1中更新过的共享变量刷新到主内存中。

将主内存中最新的共享变量的值更新到工作内存2中。

可见性

要实现共享变量的可见性,必须保证两点:

线程修改后的共享变量值能够及时从工作内存刷新到主内存中。

其他线程能够及时把共享变量的最新值从主内存更新到自己的工作内存中。

可见性的实现方式

Java语言层面支持的可见性实现方式:

Synchronized

Volatile

Synchronized实现可见性

Synchronized能够实现:

原子性(同步);

可见性

JMM关于Synchronized的两条规定:

线程解锁前,必须把共享变量的最新值刷新到主内存中;

线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(注意:加锁与解锁需要是同一把锁)

线程解锁前对共享变量得修改在下次加锁时对其他线程可见。

线程执行互斥代码的过程:

  1. 获得互斥锁

  2. 清空工作内存

  3. 从主内存中拷贝变量的最新副本到工作内存

  4. 执行代码。

  5. 将更改后的共享变量的值刷新到主内存。

  6. 释放互斥锁。

重排序

重排序:代码书写的顺序与实际执行的顺序不同,指令重排序是编译器或处理器为了提高程序性能而做的优化。

  1. 编译器优化的重排序(编译器优化)。

  2. 指令级并行重排序(处理器优化)。

  3. 内存系统的重排序(处理器优化)。

as-if-serial

as-if-serial:无论如何重排序,程序执行的结果应该与代码顺序执行的结果一致(java编译器、运行时和处理器都会保证Java在单线程下遵循as-if-serial语义)。

例子:

Int num = 1;

Int num2 = 2;

Int sum = num+num2;

单线程:第1、2行的顺序可以重排,但第3行不能

重排序不会给单线程带来内存可见性问题

多线程中程序交错执行时,重排序可能会造成内存可见性问题。

Volatile实现可见性

Volatile关键字:

能够保证volatile变量的可见性

不能保证volatile变量复合操作的原子性

Volatile如何实现内存可见性:

深入来说:通过加入内存屏障和禁止重排序优化来实现的。

对volatile变量执行写操作时,会在写操作后加入一条store屏障指令

对volatile变量执行读操作时,会在读操作前加入一条load屏障指令

通俗的讲:volatile变量在每次被线程访问时,都强迫从主内存中重读该变量的值,而当该变量发生变化时,又会强迫线程将最新的值刷新到主内存。这样任何时刻,不同线程总能看到该变量的最新值。

线程写volatile变量的过程:

  1. 改变线程工作内存中volatile变量副本的值

  2. 将改变后的副本的值从工作内存刷新到主内存

线程读volatile变量的过程:

  1. 从主内存中读取volatile变量的最新值到线程的工作内存中

  2. 从工作内存中读取volatile变量的副本。

Volatile适用场合

要在多线程中安全的使用volatile变量,必须同时满足:

1. 对变量的写入操作不依赖其当前值

2.  布尔,用来记录温度

3.该变量没有包含在具有其他变量的不变式中。

结束语:不要在意别人在背后怎么看你说你,因为这些言语改变不了事实,却可能会搅乱你的心。

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

10

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

109

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

16

2026.01.26

苹果官方查询网站 苹果手机正品激活查询入口
苹果官方查询网站 苹果手机正品激活查询入口

苹果官方查询网站主要通过 checkcoverage.apple.com/cn/zh/ 进行,可用于查询序列号(SN)对应的保修状态、激活日期及技术支持服务。此外,查找丢失设备请使用 iCloud.com/find,购买信息与物流可访问 Apple (中国大陆) 订单状态页面。

136

2026.01.26

npd人格什么意思 npd人格有什么特征
npd人格什么意思 npd人格有什么特征

NPD(Narcissistic Personality Disorder)即自恋型人格障碍,是一种心理健康问题,特点是极度夸大自我重要性、需要过度赞美与关注,同时极度缺乏共情能力,背后常掩藏着低自尊和不安全感,影响人际关系、工作和生活,通常在青少年时期开始显现,需由专业人士诊断。

7

2026.01.26

windows安全中心怎么关闭 windows安全中心怎么执行操作
windows安全中心怎么关闭 windows安全中心怎么执行操作

关闭Windows安全中心(Windows Defender)可通过系统设置暂时关闭,或使用组策略/注册表永久关闭。最简单的方法是:进入设置 > 隐私和安全性 > Windows安全中心 > 病毒和威胁防护 > 管理设置,将实时保护等选项关闭。

6

2026.01.26

2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】
2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】

铁路12306提供起售时间查询、起售提醒、购票预填、候补购票及误购限时免费退票五项服务,并强调官方渠道唯一性与信息安全。

122

2026.01.26

个人所得税税率表2026 个人所得税率最新税率表
个人所得税税率表2026 个人所得税率最新税率表

以工资薪金所得为例,应纳税额 = 应纳税所得额 × 税率 - 速算扣除数。应纳税所得额 = 月度收入 - 5000 元 - 专项扣除 - 专项附加扣除 - 依法确定的其他扣除。假设某员工月工资 10000 元,专项扣除 1000 元,专项附加扣除 2000 元,当月应纳税所得额为 10000 - 5000 - 1000 - 2000 = 2000 元,对应税率为 3%,速算扣除数为 0,则当月应纳税额为 2000×3% = 60 元。

35

2026.01.26

oppo云服务官网登录入口 oppo云服务登录手机版
oppo云服务官网登录入口 oppo云服务登录手机版

oppo云服务https://cloud.oppo.com/可以在云端安全存储您的照片、视频、联系人、便签等重要数据。当您的手机数据意外丢失或者需要更换手机时,可以随时将这些存储在云端的数据快速恢复到手机中。

121

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.9万人学习

C# 教程
C# 教程

共94课时 | 7.7万人学习

Java 教程
Java 教程

共578课时 | 52.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号