栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

线程和进程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

线程和进程

线程和进程 一、多线程技术
线程和进程

进程:

  • 是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间。

线程:

  • 是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行。一个进程最少有一个线程
  • 线程实际上是在进程基础之上进一步划分,一个进程启动后,里面的若干执行路径又可以划分成若干个线程。
线程调度

分时调度:

  • 所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。
抢占式调度:
  • 优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。

    概念:

    CPU使用抢占式调度模式再多个线程间进行高度的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而CPU在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行。其实,多线程程序并不能提高程序的运行速度,但是能够提高程序运行效率,让CPU的使用率更高。


同步与异步

同步: 排队执行,效率低但是安全

异步: 同时执行,效率高但是数据不安全

并发和并行

并发: 指两个或者多个事件在同一个时间段内发生。

并行: 指两个或多个事件在同一时刻发生(同时发生)。


二、Thread(继承) 三、Runnable(接口)

实现 Runnable 和 继承 Thread 相比有如下优势:

  1. 首先通过创建任务,然后给线程分配的方式来实现多线程,更适合多个线程同时执行相同任务的情况。
  2. 可以避免单继承带来的局限性。
  3. 任务与线程本身是分离的,提高程序的健壮性。
  4. 后续学习地址池技术,接受Runnable 类型的任务,不接受Thread 类型的线程。

创建线程类

继承式创建 Thread:

// Thread 创建线程。   这是单继承方式的创建,不推荐使用,但也能玩。
public class MyThread extends Thread{
 //run方法
 @Override
 public void run(){
     //这里的代码 就是一条新的执行路径
     for(int i = 0; i < 10; i++){
         System.out.println(i);
     }
 }
}//MyThread 线程

//调用 在main 中调用
public static void main(String[] args){
 MyThread m = new MyThread();
 // 线程启动
 m.start();
}

接口实现类 Runnable:

// 通过实现接口 Runnable 来创建线程
public class MyRunnable implements Runnable{
 //run
 @Override
 public void run(){
     for(int i = 0; i < 10;i++){
         System.out.println(i);
     }
 }
}

// 调用
public static void main(String[] args){
 // 1.创建一个任务对象
 MyRunnable R1 = new MyRunnable();
 // 2.创建一个线程,并为其分配一个任务
 Thread t = new Thread(R1);
 // 3.执行
 t.start();
}

匿名内部类的写法

//只临时使用一次,没有起名字,但也是个线程。
// 还是继承了 Thread, 属于 第一种创建方式
new Thread(){
 @Override
 public void run(){
     for(int i = 0;i<10;i++){
         System.out.pintln(i);
     }
 }
}.start();
设置和获取线程名称

设置线程名称:

// MyRunnable 这是我自定义的一个线程类
new Thread(new MyRunnable(),"线程一");

获取线程名称:

//通过Thread.currentThread() 这个静态方法获取
Thread.currentThread().getName();
线程休眠

线程休眠

// 休眠 1秒 
Thread.sleep(1000);
线程阻塞

所有比较消耗时间的操作,可以理解为阻塞。

比如常见的,读取文件操作,它会导致线程一直等待在那个位置,代码不会继续执行,除非文件读取结束。

还有,接受用户输入,它会等待在那个位置,等待用户输入。用户不输入,代码不会继续执行。

线程的中断

一个线程是一个独立的执行路径,他是否应该结束,应该由其自身决定。

stop(); // 已过时

现在,通过给线程打标记的方式 。通过这个方法就给这个属性附上值了,就算打上标记了。在某些特定的情况下,它会查看这个标记,如果有,那么就会抛出一个异常。
t1.interrupt();

例子:

//通过给 线程Thread添加 interrupt(); 线程内部会进入 catch模块,再添加return 线程就会结束 
t1.interrupt();
static class MyRunnable implements Runnable{

     @Override
     public void run() {
         for (int i = 0;i<10;i++){
             System.out.println(Thread.currentThread().getName()+":"+i);
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
//                    e.printStackTrace();
                 System.out.println("发现了中断标记,线程结束");
                 return;
             }
         }
     }
 }

这个是完整代码

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        // 线程中断
        // 一个线程是一个独立的执行路径,他是否应该结束,应该由它自身决定。

        //创建线程
        Thread t1 = new Thread(new MyRunnable());
        t1.start();
        // mian 中同步走一个循环
        for (int i =0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        // 给 t1.线程打标记。如果此时线程正在运行,就会发现标记,并且安排自己的后事
        t1.interrupt();
    }//main

    static class MyRunnable implements Runnable{

        @Override
        public void run() {
            for (int i = 0;i<10;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
//                    e.printStackTrace();
                    System.out.println("发现了中断标记,线程结束");
                    return;
                }
            }
        }//run
    }
}

守护线程

首先需要知道线程分为 守护线程 和 用户线程

用户线程: 当一个进程不包含任何存活的用户线程时,进行结束。

守护线程: 守护用户线程的,当最后一个用户线程结束时,所有守护线程自动死亡。

当主线程结束时,哪怕自己的事情没有做完,守护线程也会结束

设置守护线程:

public static void main(String[] args){
    Thread t1 = new Thread(new MyRunnable());
    // 设置为守护线程
    t1.setDaemon(true);
    t1.start();

   // mian 中同步走一个循环
        for (int i =0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
}
public class MyRunnable implements Runnable{

    @Override
    public void run() {
            for (int i = 0;i<10;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
}
关于线程安全问题

举个例子:A、B、C 三个人去ATM机取钱,A先进去取1000块,插入卡运行一般,A脚滑了。。B看见直接插队把自己的卡塞进去,也要取1000块。过了一会机器,把A的钱吐了出来,B的钱也吐了出来。但是实际上ATM里仅有1000块,那么B的1000块哪来的???

一检查发现,ATM存款显示 -1000 块,这明显不合理。所以ATM出现了“线程不安全”问题,警察就把ATM机带走了。


实际上,计算机线程运行时,A刚跑完“3.”,B就已经在跑 “2.”,C可能已经也在“2.” 。这样跑下来 A带走1000,B带走1000,C又可以带走1000,线程不安全,ATM又得再坐一年牢。

根本原因是,多个线程同时运行,去争抢操作同一个数据,那么会导致数据会出现意外的情况。
	//1. ATM 的余额	
	private int count = 1000;
	@Override
    public void run() {

        while(count > 0){
            System.out.println("取钱中");
        	//2. 机器正常运转
        	try {
            	Thread.sleep(1000);
        	} catch (InterruptedException e) {
            	e.printStackTrace();
        	}
        	//3. ATM -1000
        	count -= 1000;
        	System.out.println("取出一千,ATM还剩"+count);
        }
    }
解决线程方法

某一个线程在运行的时候,其他线程不能插足。即排队执行

解决方法一 同步代码块 线程同步:synchromized
//格式 
synchromized(锁对象){
    要被锁的区域
}

举个例子:(下面程序仅做学习 同步代码块学习。)

package 线程安全1同步代码块;


public class Demo {
    public static void main(String[] args) {
        Object o = new Object();
        // 线程不安全
        //解决方法1. 同步代码块
        // 格式: synchronized(锁对象){
        //
        // }
        // 创建线程 1 2 3
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    
    static class Ticket implements Runnable{
        // 定义票的数量 10张
        private int count = 10;
        private Object o =  new Object();

        @Override
        public void run() {
            while(true){
                //标记代码块
                synchronized (o) {
                    if (count > 0) {
                        // 卖票
                        System.out.println("正在准备卖票");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        count--;
                        System.out.println(Thread.currentThread().getName()+"出票成功,余票:"+count);
                    }else {
                        break;
                    }
                }//synchronized
            }//while
        }
    }
}

解决方法二 同步方法
//格式 
public synchronized boolean method(){
    //这里面的代码,被锁定。
    // 线程排队执行
}

举个例子:(三个窗口每个窗口售卖10张票,方法被锁定)

public class 线程安全2同步方法 {
    public static void main(String[] args) {
        Object o = new Object();
        // 线程不安全
        //解决方法1. 同步代码块
        // 格式: synchronized(锁对象){
        //
        // }
        // 创建线程 1 2 3
        //Runnable run = new Ticket();
        new Thread(new Ticket()).start();
        new Thread(new Ticket()).start();
        new Thread(new Ticket()).start();
    }

    
    public static class Ticket implements Runnable{
        // 定义票的数量 10张
        private int count = 10;
        private Object o =  new Object();

        @Override
        public void run() {
            while(true){
                boolean flag = sale();
                if(!flag){
                    break;
                }
            }//while
        }

        public synchronized boolean sale(){
            if (count > 0) {
                // 卖票
                System.out.println("正在准备卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName()+"出票成功,余票:"+count);
                return true;
            }else{
                return false;
            }
        }//sale

    }// Ticket
}
解决方法三 显式锁Lock
// 显式锁Lock子类, ReentrantLock()
Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();

举个例子:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class 显式锁 {
    public static void main(String[] args) {
        Object o = new Object();
        // 线程不安全
        //解决方法1. 同步代码块
        // 格式: synchronized(锁对象){
        //
        // }
        // 创建线程 1 2 3
        Runnable run =  new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    
    static class Ticket implements Runnable{
        // 定义票的数量 10张
        private int count = 10;
        // 显式锁
        private Lock lock = new ReentrantLock();

        @Override
        public void run() {
            while(true){
                // 上锁 ----------------------
                lock.lock();
                if (count > 0) {
                    // 卖票
                    System.out.println("正在准备卖票");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count--;
                    System.out.println(Thread.currentThread().getName()+"出票成功,余票:"+count);

                }else{
                    break;
                }
                // 解锁 -------------------------
                lock.unlock();
            }//while
        }

    }// Ticket
}

公平锁和不公平锁

公平锁 :先来先等,排队执行。

不公平锁:抢占式,谁抢上就是谁的。

显示锁实现公平锁的代码

// ReentantLock()  传一个 true ,表示公平锁
Lock lock = new ReentantLock(true);

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/591168.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号