程序、进程、线程的定义

java 继承了rabbmq cpu占用高_java


java 继承了rabbmq cpu占用高_System_02


每个线程都有一套虚拟机栈和程序计数器,而方法区和堆只有一个进程才有一套,所以方法区和堆是进程里面线程共享的,例如堆里面提供了一个实例变量每个线程都可以去修改。

多线程:

以单核CPU为例,只使用单个线程先后完成多个任务(调用多个方 法),肯定比用多个线程来完成用的时间更短,为何仍需多线程呢?

多线程程序的优点:

  1. 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
  2. 提高计算机系统CPU的利用率
  3. 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和 修改

何时需要多线程

  • 程序需要同时执行两个或多个任务。
  • 程序需要实现一些需要等待的任务时,如用户输入、文件读写
    操作、网络操作、搜索等。
  • 需要一些后台运行的程序时

多线程的创建

方式一:继承Thread类

  • 多线程的创建:
  • 1.创建一个继承于Thread类的子类
  • 2.重写Thread类的run()→ 将此线程执行的操作声明在run()
  • 3.创建Thread类的子类的对象
  • 4.通过此对象调用start()
package com.acoffee.java;

/**
 * 多线程的创建,方式一:继承Thread类
 * 1.创建一个继承于Thread类的子类
 * 2.重写Thread类的run()→ 将此线程执行的操作声明在run()
 * 3.创建Thread类的子类的对象
 * 4.通过此对象调用start()
 * @author acoffee
 * @create 2020-09-24 16:46
 */
public class ThreadTest {
    public static void main(String[] args) {
        //3.创建Thread类的子类的对象
        evenNmber t1 = new evenNmber();
        //4.通过此对象调用start():
        t1.start();
        //如下操作仍然是在main线程中执行的
        for (int i = 0;i < 100;i++){
            if(i % 2 != 0){
                System.out.println(i + "***main()***");

            }
        }
    }
}

//1.创建一个继承于Thread类的子类
class evenNmber extends Thread {
    //2.重写Thread类的run()→ 将此线程执行的操作声明在run()
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(i);
            }
        }
    }
}

使用匿名方法去调用线程

new Thread(){run方法体}.start();
package com.acoffee.exer;

/**
 * 练习:创建两个分线程,其中一个线程遍历100以内的
 * 偶数,另一个遍历100一类的奇数
 * @author acoffee
 * @create 2020-09-24 18:13
 */
public class ThreadTest {
    public static void main(String[] args) {
//        Mythread1 m1 = new Mythread1();
//        Mythread2 m2 = new Mythread2();
//
//        m2.start();
//        m1.start();

        //使用匿名的方法:创建Thread类的匿名子类的方式
        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    if (i % 2 == 0) {
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                    }
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run() {

                for (int i = 0; i < 100; i++) {
                    if (i % 2 != 0) {
                        System.out.println(Thread.currentThread().getName() + ":" + i);

                    }
                }
            }
        }.start();
    }
}

//遍历100以内的偶数
class Mythread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
               System.out.println(Thread.currentThread().getName()+":"+i);
           }
        }
    }
}

//遍历100以内的奇数
class Mythread2 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 != 0) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}

方式二:实现Runnable接口

  • 创建多线程的方式二:
  • 1.创建一个实现了Runable接口的类
  • 2.实现类去实现Runable中的抽象方法:run()
  • 3.创建实现类的对象
  • 4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
  • 5.通过Thread类的对象调用start()
package com.acoffee.java;

/**
 * 创建多线程的方式二:实现Runnable接口
 * 1.创建一个实现了Runable接口的类
 * 2.实现类去实现Runable中的抽象方法:run()
 * 3.创建实现类的对象
 * 4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
 * 5.通过Thread类的对象调用start()
 * @author acoffee
 * @create 2020-09-24 20:58
 */

//1.创建一个实现了Runable接口的类
class Mthread implements Runnable{

    //2.实现类去实现Runable中的抽象方法:run()
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}
public class ThreadTest1 {
    public static void main(String[] args) {
        //3.创建实现类的对象
        Mthread mthread = new Mthread();
        //4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
        Thread t1 = new Thread(mthread);
        t1.setName("线程一");
        //5.通过Thread类的对象调用start():调用了Runnable类型的target(mthread)的run()
        t1.start(); //谁start的谁就是线程

        //在启动一个线程,遍历100以内的偶数
        Thread t2 = new Thread(mthread);
        t2.setName("线程二");
        t2.start();
    }
}

Thread类的有关方法

java 继承了rabbmq cpu占用高_多线程_03


java 继承了rabbmq cpu占用高_多线程_04

上述方法实现的代码:

package com.acoffee.exer;

/**
 * @author acoffee
 * @create 2020-09-24 18:56
 */


public class ThreadMethodTest {
    public static void main(String[] args) {
        //通过构造器给线程命名:
        Mythread3 m1 = new Mythread3("thread:");

        //setName就是name属性的set方法
        //getName就是name属性的get方法
        m1.setName("线程一");

        m1.start();
        //给主线程命名:
        Thread.currentThread().setName("主线程");
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
            if (i == 20) {
                try {
                    //在线程A中调用线程B的join方法,此时线程A就进入阻塞状态
                    //直到线程B完全执行完以后,线程A才结束阻塞状态。
                    m1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println(m1.isAlive());//判断线程是否存活,即是否运行完
    }
}

class Mythread3 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                //这里是不能用throw的方法去抛异常的
                //因为我们是继承Thread中的run方法的
                //因为Thread类中都没有抛异常,子类抛
                //的异常是不能大于父类的。
                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+":"+i);
            }

            if (i % 20 == 0){
                //释放当前cpu的执行:相当于重新分配执行权,但是还是有可能分到这个线程
                yield();
            }
        }
    }
    //命名的构造器
    public Mythread3(String name){
        super(name);
    }
}

线程优先级:

java 继承了rabbmq cpu占用高_java_05


高优先级的线程要抢占低优先级线程cpu的执行权。但是只是从概率上讲,高优先级的线程高概率的情况下被执行,并不意味着只有高优先级的线程执行完后,低优先级才执行。

//获取优先级
System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+":"+i);
//设置优先级
m1.setPriority(Thread.MAX_PRIORITY);

练习:

方式一实现:

package com.acoffee.java;

/**
 * 例子:创建三个窗口买票,总票数为100张
 * @author acoffee
 * @create 2020-09-24 20:35
 */

class window extends Thread{

    private static int ticket = 100;

    @Override
    public void run() {
    while (true){
        if(ticket > 0){
            System.out.println(getName()+":卖票,票号为:"+ticket);
            ticket--;
        }else{
            break;
            }
        }
    }
}

public class WindowTest {
    public static void main(String[] args) {
        window w1 = new window();
        window w2 = new window();
        window w3 = new window();

        w1.setName("窗口1");
        w2.setName("窗口2");
        w3.setName("窗口3");

        w1.start();
        w2.start();
        w3.start();
    }
}

执行结果:

java 继承了rabbmq cpu占用高_System_06


从执行结果我们可以看到此方法存在线程不安全的情况。我们在同步处在进行处理。

方式二实现:

package com.acoffee.java;

/**
 * @author acoffee
 * @create 2020-09-24 21:25
 */
public class WindowTest1 {
    public static void main(String[] args) {
        Window1 w = new Window1();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();

    }

}
class Window1 implements Runnable{
    private int ticket = 100;//这里不用加static因为这里只创建了一个window对象

    @Override
    public void run() {
        while (true){
            if(ticket > 0){
                System.out.println(Thread.currentThread().getName()+":"+ticket);
                ticket--;
            }else{
                break;
            }
        }
    }
}

比较创建线程的两种方式:

开发中,优先选择:实现Runnable接口的方式
原因:1.实现的方式没有类的单继承性的局限性
2.实现的方式更适合来处理多个线程有共享数据的情况

联系:public class Thread implements Runnable
相同点:两种方式都需要重写run( ),将线程要执行的逻辑声明在run( )中。
目前这两种方式,要想启动线程,都是调用的Thread类中的start( )。

每日一练:

1. 谈谈你对程序、进程、线程的理解
程序(program):即指一 段静态的代码,静态对象。
进程(process):是程序的一次执行过程,或是正在运行的一个程序。
线程(thread):进程可进一步细化为线程,是一个程序内部的一条执行路径。
一个Java应用程序java.exe,其实至少有三个线程:main()主线程,gc() 垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程。 Java中的线程分为两类:一种是守护线程,一种是用户线程。

2. 代码完成继承Thread的方式创建分线程,并遍历100以内的自然数

class ThreadTest {
	public static void main(String[] args){
		thread1 t1 = new thread1();
		t1.start();
	}
}

class thread1 extends Thread{

	public void run(){
		for(int i = 0;i < 100;i++){
			if(i % 2 == 0){
				System.out.println(i);
			}	
		}
	}
}

3. 代码完成实现Runnable接口的方法创建分线程,并遍历100以内的自然数

class ThreadTest {
	public static void main(String[] args){
		//创建实现类的对象
		thread2 t1 = new thread2();
		//传入Thread构造器
		Thread t2 = new Thread(t1);
		t2.start();
	}
}

class thread2 implements Runnable{
	public void run(){
		for(int i = 0;i < 100;i++){
			if(i % 2 == 0){
				System.out.println(i);
			}	
		}
	}
}

4. 对比两种创建方式
开发中,优先选择:实现Runnable接口的方式
原因:1.实现的方式没有类的单继承性的局限性
2.实现的方式更适合来处理多个线程有共享数据的情况

联系:public class Thread implements Runnable
相同点:两种方式都需要重写run( ),将线程要执行的逻辑声明在run( )中。

5. 说说你对IDEA中Project和Module的理解
Project是IDEA中最高层级的,一个Project中可以有多个Module
eclipse中的workspace就相当于IDEA中的Project,eclipse中的project就相当于IDEA中的Module