进程和线程


进程和线程的区别:

  • 进程:进程是操作系统中运行的一个任务(一个应用程序运行在进程中)
    进程是一块包含了某些资源的内存区域。
    当操作系统创建一个进程后,该进程会自动申请一个名为主线程的线程。
  • 线程:进程中所包含的一个或多个执行单元称为线程。
    线程只能归属一个进程并且它只能访问该进程所拥有的的资源
    一个进程中可以包含多个线程。

    一个进程中可以包含多个线程。
    线程的划分尺度小于进程,使得多线程程序的并发性提高。
    进程在执行过程中拥有独立的内存单元,而多个线程共享此内存,从而极大提高了程序的运行效率。

线程不能独立执行。

并发原理:多个线程同时运行 只是我们感官上的一种表现。事实上线程是并发运行的,当获得了时间片段的线程被 CPU 运行,而其他线程则全部等待,微观上说是“走走停停”,宏观上说是都在运行,但绝对不是绝对意义上的同时发生。

创建线程(两种方式)
1.Thread 类是线程类,每一个实例表示一个可运行的线程。可以通过集成该类并重写 run()方法来定义一个具体线程。

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("\" " + i + "号, 你是谁啊?\"");
        }
    }
}

class MySecondThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(i + " 号:\"我是你爸爸" + (i == 0 ? "" : " + " + i) + "!\"");
        }
    }
}

Thread t1 = new MyThread();
Thread t2 = new MySecondThread();//只是就绪,并没有执行
t1.start();//调用 start 方法执行而不是 run 方法
t2.start();

Thread 创建线程
查资料了解“耦合”

2.实现 Runnable 接口, 并重写 run() 来定义线程,然后再创建线程时将 Runnable 的实例传入并启动线程。

通常我们通过匿名内部类方式创建线程。

start() 和 run()
启动线程时调用 start() 而不是直接调用 run()方法。
start() 会将当前线程纳入线程调度,使得当前线程可以运行,当线程获取时间片段之后会自动调用 run() 方法。

常用方法
public static Thread currentThread()返回对当前正在执行的线程对象的引用。

返回:
当前执行的线程。

public long getId()返回该线程的标识符。线程 ID 是一个正的 long 数,在创建该线程时生成。线程 ID 是唯一的,并终生不变。线程终止时,该线程 ID 可以被重新使用。

返回:
该线程的 ID。

public final String getName()返回该线程的名称。

返回:
该线程的名称。

public final void setName(String name)改变线程名称,使之与参数 name 相同。
首先调用线程的 checkAccess 方法,且不带任何参数。这可能抛出 SecurityException。

参数:
name - 该线程的新名称。

public final boolean isAlive()测试线程是否处于活动状态。如果线程已经启动且尚未终止,则为活动状态。

返回:
如果该线程处于活动状态,则返回 true;否则返回 false。

public final boolean isDaemon()测试该线程是否为守护线程。

返回:
如果该线程是守护线程,则返回 true;否则返回 false。

public boolean isInterrupted()测试线程是否已经中断。线程的中断状态 不受该方法的影响。
线程中断被忽略,因为在中断时不处于活动状态的线程将由此返回 false 的方法反映出来。

返回:
如果该线程已经中断,则返回 true;否则返回 false。

public static void sleep(long millis)
throws InterruptedException 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。该线程不丢失任何监视器的所属权。

参数:
millis - 以毫秒为单位的休眠时间。

可以导致调用该方法的线程进入阻塞状态,阻塞指定的毫秒值,当超时后,线程会自动回到就绪状态(Runnable)等待重新分配时间片段来继续执行

守护线程

又称为后台线程。
当一个进程中的所有前台线程都结束,进程结束,此时无论是否进程中是否有后台线程,都会被强制结束。
默认穿件出来的线程都是前段线程,后台线程需要使用 setDaemon(true) 单独的设置。

public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
该方法必须在启动线程前调用。

该方法首先调用该线程的 checkAccess 方法,且不带任何参数。这可能抛出 SecurityException(在当前线程中)。

join
方法会将调用该方法的线程至于阻塞状态 ,知道其等待的线程执行完毕之后才会借出阻塞继续运行

public static void yield()暂停当前正在执行的线程对象,并执行其他线程。

同步操作
有先后顺序,性能稍慢,相当于你干完,我在赶

一部操作
多线程并发曹组哦,性能少块,相当于大家一起干,各干各的

线程同步:多个线程并发,读写同一个资源,会发生线程安全问题。
常见问题:

  • 多个示例共享实例变量。
  • 多个线程共享静态的公共的资源。

若想解决线程安全问题,需要将线程一部操作编程同步操作。

线程池

当一个程序中若创建大量的线程,并在执行结束后销毁,会给系统带来过度消耗资源,从而可能导致系统崩溃。所以我们应该使用线程池来解决这个问题

1.控制线程数量
2.重用线程

并发量大导致 CPU 过度切换,导致拖慢系统,耗费系统资源。严重时可能会导致系统崩溃,频繁创建与销毁线程也会给系统带来负担。

原理

首先会创建一些线程,他们的集合称为线程池。当服务器接收到一个客户请求后,就从线程池中取出一个空闲的线程,去执行该任务,服务完毕后,该线程归还给线程池,而不是关闭销毁。

创建线程池

ExecutorService service = Executors.newFixedThreadPool(2); 
service.execute(thread);//执行线程
service.shutdown();//当线程池中所有任务执行结束后,结束线程池
service.shutdownNow();//立即中断正在运行的线程,并关闭线程池。

常用 API
StringBuffer 线程安全,同步处理,性能稍慢
StringBuilder 线程不安全,异步处理,性能稍快。

对于集合 Map 而言,可以使用 Collections 提供的静态方法对已有的集合或 Map 进行转换成线程安全的集合或 map

//ArrayList 和 LinkedList 都是非线程安全的

List《String》 list = new Array
list.add

System.out.println(list);
//将给定的 list 集合转换成线程安全的 list 集合
list = Collections.synchronizedList(list);

Set HashMap 同上

HashTable 是线程安全的。


文章作者: CrazyBunQnQ
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 CrazyBunQnQ !
  目录