Java进程线程介绍创建和执行销毁并理解线程安全和线程池 Native Method

这篇具有很好参考价值的文章主要介绍了Java进程线程介绍创建和执行销毁并理解线程安全和线程池 Native Method。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.进程和线程

进程和线程都是一个控制流程。
一个进程通常对应于一个程序。
一个程序可以由多个不同的线程构成。
一个进程就是一个应用程序
一个应用程序面对多个用户则多个进程
一个进程则多个线程
多个线程共享资源且携带数据操作
多进程资源隔离

2.多线程的核心

多线程的核心在于多个代码块并发执行,本质特点在于各代码块之间的代码是乱序执行的。

3.操作系统的多任务–以非常小的时间间隔交替执行

进程:正在进行的程序
现在使用的操作系统都是多任务的,即能够 同时 执行多个应用程序。实际是操作系统负责对CPU等设备资源进行分配和管理,虽然这些设备某一时刻只能做一件事情,但以非常小的时间间隔交替执行多个程序,就给人同时执行多个程序的感觉

4.native 修饰的方法

Native Method 调用java外的程序包,其中包含
一个Native Method就是一个java调用非java代码的接口
一个native method方法可以返回任何java类型,包括非基本类型,而且同样可以进行异常控制。

5.Thread

一个Thread类的对象代表一个线程,而且只能代表一个线程。
通过Thread类和它定义的对象,我们能获得当前线程对象、获取某一线程的名称、可以实现控制线程暂停一段时间等功能
Java进程线程介绍创建和执行销毁并理解线程安全和线程池 Native Method

创建线程的两种方式

共同点都是自定义线程类重写run()方法 并且通过 new Thread (线程对象的实例).start() 方法启动线程和创建一个实例线程启动运行run()方法,真正实现多线程的方式实现

1.普遍采用实现Runnable接口的方式

public class MyThreadImp implements Runnable {
    @Override
    public void run() {
        System.out.println("执行实现Runable接口的MyThreadImp的类中run()方法");
    }

    public static void main(String[] args) {
        MyThreadImp myThreadImp = new MyThreadImp();
        Thread thread =new Thread(myThreadImp);
        thread.start();//执行实现Runable接口的MyThreadImp的类中run()方法
    }
}

2.继承Thread方式

public class MyThread extends  Thread{
	//等待线程调用
    public  void  run (){
        System.out.println("执行了Mythread的run() 方法");
        System.out.println(currentThread());
    }
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread  = new Thread(myThread);
        thread.start();// 执行了Mythread的run() 方法
    }
}

6.自定义线程用 new Thread(Runnable target) 启动源码分析

6.1-new Thread(myThread)

主要
1启动线程;
thread.start();
private native void start0(); 调用外部接口启动线程 可能涉及到 硬件或者动态链接库函数等待

 public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

6.2对实例 myThread 创建线程 并给 Thread类 成员变量 target 赋予当前对象实例

创建实例的线程(如果必要可以给线程等级,权限)
/* What will be run. */ 运行哪一个对象实例
private Runnable target;


 public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    
private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }

 private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;
        //创建线程
        Thread parent = currentThread()
 		。。。。。。
       //  成员变量 target 赋予当前对象实例
        this.target = target;
        //获取守护进程
        this.daemon = parent.isDaemon();
        //获取进程权限
        this.priority = parent.getPriority();
		。。。。。。
		//省略部分代码
		。。。。。。
        /* Set thread ID */
        //获取下个线程id
        tid = nextThreadID();
    }

7.实现接口Runnable和继承Thread类的区别

①处理和共享同一资源对多个相同的程序代码的线程
②避免由于java单继承特征带来的局限性
③增强代码的健壮性和灵活性可以多个线程共享,代码和数据是独立的

8.启动线程通过start()和 run () 区别

start方法:
通过该方法启动线程的同时也创建了一个线程.真正实现了多线程。并不等待run方法法中的代码执行完毕,就可以接着执行下面的代码。此时start0的这个线程处于就绪状态.等待到CPU的时间片后就会执行其史的run方法。.这个run方法 含了要执行的这个线程的内容, run()方法运行结束,此线程也就终止了。
run方法:
通过run方法启动线程其实就是调用一个类中的方法,当作普通的方法的方式调用。并没有创建一个线程,程序中依旧只有一个主线程,必须等到run()方法里面的代码执行完毕,才会继续执行下面的代码,这样就没有达到写线程的目的。

 public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
    private native void start0();

当一个start()线程启动的时候,它的状态〈threadStatus)被设置为О(即线程为NEW状态),如果不为0,则抛出llegalThreadStateException异常。
正常的话,将该线程加入线程组,最后尝试调用start0方法,而start0方法是私有的native方法(Native Method是一个java调用非java代码的接口)。
start调用后,线程出于就绪状态RUNNABLE,等分配到cpu时间片时系统会调用thread的run()方法,而这个方法其实只是调用runnable里面自己实现的run()方法。


public class Test7Thread extends  Thread{
    //
    public  void  run (){
        System.out.println("执行了Test7Thread");
        System.out.println(currentThread());
    }

    public static void main(String[] args) {
        Test7Thread  test7Thread = new Test7Thread();
        test7Thread.start();//执行了Test7Thread
    }

}
public class test5 {
    public static void main(String[] args) {
        Thread thread  = new Thread(){
            public  void  run(){
                pong();
            }
        };
        thread.start();//启动线程start方法  启动run方法
        thread.run();//启动run方法  启动线程start方法
        System.out.println("启动线程start方法");
    }

    static void pong (){
        System.out.println("启动run方法");
    }
}

9.Thread类target

target - 其 run 方法被调用的对象。
首先run方法是接口 Runnable 中,而Thread 实现此接口并重写run方法
与此同时创建创建新执行线程有两种方法。
一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。
创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。采用这种风格的同一个例子如下所示:
不管是继承还是实现接口的都是调用了run() 方法 ,谁去调用的??是创建的类的对象调用,
故 target - 其 run 方法被调用的对象。

Thread类中
 @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

10.1线程之一经典的银行转账线程问题

有一个银行账户,还有余额1100元,现在A通过银行卡从中取1000元,而同时另外一个人B通过存折也从这个账户中取1000元。取钱之前,要首先进行判断:如果账户中的余额大于要取的金额,则可以执行取款操作,否则,将拒绝取款。
我们假定有两个线程来分别从银行卡和存折进行取款操作,当A线程执行完判断语句后,获得了当前账户中的余额数(1000元),因为余额大于取款金额,所以准备执行取钱操作(从账户中减去1000元),但此时它被线程B打断,然后,线程B根据余额,从中取出1000元,然后,将账户里面的余额减去1000元,然后,返回执行线程A的动作,这个线程将从上次中断的地方开始执行:也就是说,它将不再判断账户中的余额,而是直接将上次中断之前获得的余额减去1000。此时,经过两次的取款操作,账户中的余额为100元,从账面上来看,银行支出了1000元,但实际上,银行支出了2000元。

10.2线程之二 经典的买火车票问题

方法一

=========继承Thread==========模拟4个售票窗口共同卖100张火车票的程序=============
public class TicketThread {
    public static void main(String[] args){
        // 执行继承Thread的线程
        new MyThread().start();//售票窗口1
        new MyThread().start();//售票窗口2
        new MyThread().start();//售票窗口3
        new MyThread().start();//售票窗口4
    }
}

class MyThread extends Thread {
    // 车票数量
    private int tickets = 100;

    public void run() {
        while (tickets > 0) {
            System.out.println(this.getName() + " 卖出第 " + tickets-- + "张火车票.");
        }
    }
}

方法二

==========实现Runnable接口=========模拟4个售票窗口共同卖100张火车票的程序=============
public class TicketRunnable {
    public static void main(String[] args) {
        //实现Runnable接口实现类
        myRunnable myR = new myRunnable();
        new Thread(myR).start();
        new Thread(myR).start();
        new Thread(myR).start();
        new Thread(myR).start();
    }
}
class myRunnable implements Runnable {
    //火车票数量
    private  int tickets = 100; 
    public void run() {
        while (tickets > 0) {
            System.out.println(Thread.currentThread().getName()+"卖出第["+(tickets--) +"]张火车票.");
        }
    }
}

11工作中,几乎所有的多线程应用都用实现Runnable这种方式

把虚拟CPU(线程)同程序的代码、数据有效的分离
健壮、灵活
编写简单,可以直接操纵线程,无需使用Thread.currentThread()。

12关于线程安全问题

多线程共享数据时的问题

在售票程序中,System.out.println(Thread.currentThread().getName()+“卖出第[”+(tickets–) +“]张火车票.”);这段代码执行时候,极有可能出现一种意外。就是同一张票可能会被打印两次或多次,也可能出现打印0或负数的情况。
假设:当tickets的值为1的时候,线程1刚执行完if(tickets>0),正准备执行下面的代码,这时,操作系统将CPU切换到了线程2上执行,此时tickets的值仍是1,线程2执行完以下代码,CPU切回线程1,
线程1不再执行if(tickets>0),继续往下执行,此时意外出现。
可以使用sleep()来制造线程中这种切换的错误。
这种错误也就是我们常说的"线程安全

解决之道–思想–线程同步

多个线程都想对同一个资源或代码块的时,此时此刻只能被单独一个线程执行完毕再释放出去待下一线程继续使用这个代码块,这就是线程同步。
比如:一张火车票只有可能出售给一位旅客,下一个旅客只能等待下一个线程继续操作申请另一张票

解决之道–具体实现

将具有原子性的代码放入synchronize语句内,形成同步代码块。就可以保证线程安全了。
每个对象都有一个标志位(锁旗标),该标志位有两个状态0、1,其开始状态为1,当执行synchronized(Object)语句后,Object对象的标志位变为0状态,直到执行完整个synchronized语句中的代码块后才又回到1状态。一个线程执行到synchronized(Object)的时候,先检查Object对象的标志位,0表示有线程在执行,这个线程将暂时阻塞,让出CPU资源,直到另外线程执行完有关代码,将Object对象状态恢复到1状态,这个阻塞才被取消,然后线程开始执行,同时将Object对象的标志位变为0,防止其他线程再进入有关的同步代码块中。
当线程执行到synchronized的时候,如果得不到锁标记,这个线程会被加入到一个与该对象的锁标记相关连的等待线程池当中,等待锁标记。当线程执行完同步代码,就会释放锁标记。一个刚释放了锁标记的线程可以马上再次获得锁标记,当同步块遇到break或抛出exception时,线程也会释放锁标记。

wait、notify、notifyAll这三个方法只能在synchronized方法中调用,即无论线程调用一个对象的wait还是notify方法,该线程必须先得到该对象的锁旗标,这样,notify只能唤醒同一对象监视器中调用wait的线程。

所以,如果确定程序没有安全性的问题,就没有必要使用同步。

ArrayList    Vector(线程同步)
同步是以牺牲程序的性能为代价的。
所以,如果确定程序没有安全性的问题,就没有必要使用同步。
synchronized还可以作用在方法上面,用来实现线程的同步
同步块越短越好,锁力度过粗容易导致同步严重,力度过细容易发生死锁问题
Synchronized(this){--粗
	System.out.println("hello");
	System.out.println("world");
}
--------------------------------
Synchronized(this){--细
	System.out.println("hello");
}
System.out.println("world");
--------------------------------
如果是静态方法则没有实例,则锁类对象this.getClass
一个类不管有多少个实例,只有一个类对象.
	Synchronized(this.getClass()){}

13.死锁

是指两个线程,都相互等待对方释放lock
是不可测知或避开的
应采取措施避免死锁的出现

14.线程间的通信

Object 类定义了 wait()、notify() 和 notifyAll() 方法。可以让线程相互通知事件的发生。要执行这些方法,必须拥有相关对象的锁。
wait() 会让调用线程休眠,直到用 Thread.interrupt() 中断它 或者wait经过了指定的时间 或者另一个线程用 notify() 或 notifyAll() 唤醒它。
当对某个对象调用 notify() 时,如果有任何线程正在通过 wait() 等待该对象,那么就会唤醒其中一个线程。当对某个对象调用 notifyAll() 时,会唤醒所有正在等待该对象的线程。
wait、notify、notifyAll这三个方法只能在synchronized方法中调用,即无论线程调用一个对象的wait还是notify方法,该线程必须先得到该对象的锁旗标,这样,notify只能唤醒同一对象监视器中调用wait的线程。

package com.thread;

class Product{
    private String name;
    private String price;
    private int count;
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
    public void setPrice(String price){
        this.price = price;
    }
    public String getPrice(){
        return this.price;
    }
    public void setCount(int count){
        this.count = count;
    }
    public int getCount(){
        return this.count;
    }
    public String toString(){
        return "产品名称:"+this.name+" 价格:"+this.price+" 数量:"+this.count;
    }

    private boolean flag = false;
    public synchronized void put(String name,String price){
        try{
            if(flag){
                //如果有产品就不继续生产
                wait();
            }
            System.out.print("***生产者开始生产-->");
            this.setName(name);
            this.setPrice(price);
            //生产产品数量加1
            this.setCount(this.getCount()+1);
            System.out.println(this);
            flag = true;//生产完毕更改标志
            notify();//通知消费者消费
        }catch(Exception e){
           e.printStackTrace(); 
        }
    }

    public synchronized void get(){
        try{
            if(!flag){
                wait();
               }
            System.out.print("--消费者开始消费产品-->");
            //消费一个产品数量减 1
            this.setCount(this.getCount()-1);
            System.out.println(this);
            flag = false;//消费完,更改标志;
            notify();//通知生产者继续生产
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

class Producter implements Runnable{
    private Product p;
    public Producter(Product p){
        this.p = p;
    }
    public void run(){
        int i=0,n=0;
        while(n<5){
            n++;
            if(i==0){
                p.put("包子","1");
            }else{
                p.put("馒头","2");
            }
            //实现交替生产效果
            i = (i+1)%2;
        }
    }
}

class Consumer implements Runnable{
    private Product p;
    public Consumer(Product p){
        this.p = p;
    }
    public void run(){
        int n = 0;
        while(n<5){
            n++;
            p.get();
        }
    }
}

public class TestThread{
    public static void main(String[] args){
        Product p = new Product();
        new Thread(new Producter(p)).start();
        new Thread(new Consumer(p)).start();
    }
}

15.同步实现方式–线程的状态

synchronized,wait和notify,notityAll。

Java进程线程介绍创建和执行销毁并理解线程安全和线程池 Native Method文章来源地址https://www.toymoban.com/news/detail-430795.html

到了这里,关于Java进程线程介绍创建和执行销毁并理解线程安全和线程池 Native Method的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java多线程 - 创建的三种方式介绍

    什么是线程 ? 线程(thread)是一个程序内部的一条执行路径。 我们之前启动程序执行后,main方法的执行其实就是一条单独的执行路径。 程序中如果只有一条执行路径,那么这个程序就是单线程的程序。 什么是多线程 ? 多线程是指从软硬件上实现多条执行流程的技术。 方式一

    2024年02月20日
    浏览(33)
  • Java进程ProcessBuilder类的介绍及使用,ProcessBuilder调用外部程序执行shell命令Linux命令

    目录 ProcessBuilder类的介绍及使用 【前言】 【正文】 --构造方法-- --常用方法-- --使用技巧-- --调用本地Shell命令,实例-- 【总结】 【注意】         在做一个项目的时候需要用到运行时动态执行JAVA命令,一开始的思路是运行时生成bat脚本,然后通过Runtime类的exec方法之行

    2024年02月09日
    浏览(35)
  • Java - JUC(java.util.concurrent)包详解,其下的锁、安全集合类、线程池相关、线程创建相关和线程辅助类、阻塞队列

    JUC是java.util.concurrent包的简称,在Java5.0添加,目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题 java.lang.Thread.State tools(工具类):又叫信号量三组工具类,包含有 CountDownLatch(闭锁) 是一个同步辅助类,在完成一组正在其他线程中

    2024年02月05日
    浏览(29)
  • 【多线程系列-01】深入理解进程、线程和CPU之间的关系

    多线程系列整体栏目 内容 链接地址 【一】深入理解进程、线程和CPU之间的关系 https://blog.csdn.net/zhenghuishengq/article/details/131714191 【二】java创建线程的方式到底有几种?(详解) https://blog.csdn.net/zhenghuishengq/article/details/127968166 【三】深入理解java中线程的生命周期,任务调度 ht

    2024年02月16日
    浏览(35)
  • 什么是线程?线程和进程的关系?如何创建/查看线程?

    1.1.1 什么是线程 进程进一步细化为线程, 是程序内部的一条执行路径. 一个进程中至少有一个线程. 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间\\\"同时\\\"执行多份代码. 1.1.2 线程存在的意义 ① “并发编程\\\"成为\\\"刚需” 单核 CPU 的发展遇到了瓶颈. 要想提高算力, 就

    2024年02月15日
    浏览(29)
  • 僵尸进程的避免 守护进程的创建 线程的创建,阻塞,数据传递 5.15

    父子进程相关知识: exit(int status):结束当前调用的进程,自动刷新缓存 标准库函数 头文件:#include stdlib.h _exit(int status) : 结束当前调用的进程,不刷新缓存 系统调用函数 头文件:#include unistd.h 子进程先于父进程结束,父进程没有回收子进程的剩余资源 1、子进程结束,通知

    2024年02月05日
    浏览(30)
  • 【从零学习python 】84.深入理解线程和进程

    进程,能够完成多任务,比如在一台电脑上能够同时运行多个QQ。 线程,能够完成多任务,比如一个QQ中的多个聊天窗口。 进程是系统进行资源分配和调度的一个独立单位。 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程

    2024年02月11日
    浏览(31)
  • 【Linux】进程与可执行程序的关系&&fork创建子进程&&写实拷贝的理解

            系统会将此时在系统运行的进程的各种属性都以文件的形式给你保存在系统的proc目录下。 运行一个程序的时候,本质就是把磁盘中的程序拷贝到内存中,当一个进程运行起来的时候,它本质已经和磁盘中的可执行程序没有直接关系了。   当前我的myprocess程序正在运

    2024年03月19日
    浏览(31)
  • 深入理解高并发编程 - 线程的执行顺序

    在Java中,线程的执行顺序是由操作系统的调度机制决定的,具体顺序是不确定的,取决于多个因素,如操作系统的调度策略、线程的优先级、线程的状态转换等。因此,不能对线程的执行顺序做出可靠的假设。 以下是一个简单的Java代码示例,演示了多个线程的执行顺序是不

    2024年02月14日
    浏览(42)
  • 深入理解操作系统中进程与线程的区别及切换机制(上)

    所谓进程,大家可以理解为我们打开的应用程序,如微信、QQ、游戏等,但也有系统应用是我们看不见的,可以打开任务管理器一探究竟,我们写的代码程序在服务器上在不运行的情况下,它就是一个二进制文件,并不是进程! 一个进程可以包含一个或者多个线程,但对于

    2024年02月11日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包