Java多线程(基础)

什么是程序,进程和线程?

程序:是一组指令的集合(如我们写的代码),它静态存储于诸如磁盘之类的存储器里。

当一个程序被操作系统执行时,它就会被载入内存空间,并在逻辑上产生一个独立的实例,这就是进程。

进程:是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例,即运行中的程序
通常由程序、数据和进程控制块(Process Control Block,PCB)组成的,PCB时进程存在的唯一标志。

线程:线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。
线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理。

Java中的多线程

其实在Java中的多线程是模拟出来的,实际上是并发执行的,真正的多线程是指多个CPU,即多核。如果是模拟出来的多线程,即一个CPU的情况下,在同一个时间点,CPU只能执行一个代码,由于切换的很快,所以就有同时执行的错觉

并发: 多个任务交替执行,多任务之间还是串行的。
容易与 并发 混淆在一起的概念-------并行
并行: 多个任务同时执行。

多线程实现方式

1、继承Thread类,重写run方法
public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0){
                System.out.println(Thread.currentThread().getName()+": "+i);
            }
        }
    }
    public static void main(String[] args) {
        new MyThread().start();  /* 线程启动方式,调用线程类的 start() 方法 */
    }
}

运行结果
在这里插入图片描述

下面两句代码有什么区别?
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+": "+1);
    }
    public static void main(String[] args) {
    	/** 这两句 **/
        new MyThread().start();
        new MyThread().run();
    }
}

运行结果
在这里插入图片描述
start() : 它的作用是启动一个新线程,新线程会执行相应的run()方法。start()不能被重复调用。
而一启动线程,线程会自动执行线程里面的 run() 方法
run() : run()就和普通的成员方法一样,可以被重复调用。单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程。

为什么呢?

当你启动线程,使用start(),系统会把run()方法当成线程执行体来处理,这是正常的,也是正确的情况。但是,当你启动线程时,调用run()方法,系统run()方法会立即执行,但是这时候系统会把run()方法当成普通的方法,线程对象也当成一个普通对象。

如果不了解这段话,可以点这里,了解一下

所以出现一个是main线程调用,一个是新的线程调用。由于主线程的优先级比其他线程高,所以比较容易抢占资源,优先运行。

2、实现Runnable接口,重写run方法

启动线程,使用静态代理

  1. 创建真实角色
  2. 创建代理角色 +真实角色引用
  3. 调用.start() 启动线程
package test;

public class MyThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0){
                System.out.println(Thread.currentThread().getName()+": "+i);
            }
        }
    }
    public static void main(String[] args) {
        Runnable pro = new MyThread();
        new Thread(pro).start();
    }
}

3、使用Callable和Future创建线程 重写call方法(了解)
public class MyThread implements Callable<String> {
    private String str;

    public MyThread(String str){
        this.str = str;
    }
    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        return "call: "+str;
    }

    public static void main(String[] args) throws ExecutionException,InterruptedException {
        Callable callable = new MyThread("hello world");
        FutureTask<String> task = new FutureTask(callable);
        long beginTime = System.currentTimeMillis();
        new Thread(task).start();
        
		//获取call()方法的返回值
        String result = task.get();
        System.out.println("task result = "+result);
        System.out.println("use time="+(System.currentTimeMillis()-beginTime));
    }
}

运行结果
在这里插入图片描述

常见的线程方法

  • currentThread()
    返回当前正在执行的线程对象
  • getName()
    获取线程名称
  • setName(String name)
    设置线程名称
  • isAlive()
    判断线程当前状态,若执行状态则返回true,反之,返回false
public static void main(String[] args) throws InterruptedException {
        //实现Runnable接口
        MyThread t1 = new MyThread();
        Thread proxy = new Thread(t1,"线程t1");
        proxy.setName("Thread1");
        System.out.println(proxy.getName());
        System.out.println(Thread.currentThread().getName());  //main

        proxy.start();
        System.out.println("启动后的状态:"+proxy.isAlive()); //true
        Thread.sleep(200);
        t1.stop();
        Thread.sleep(100);
        System.out.println("停止后的状态:"+proxy.isAlive()); //false
    }
  • setPriority() & getPriority()

    setPriority(int newPriority):设置线程的优先级;
    getPriority():获取线程的优先级;

什么是线程优先级?
线程优先级是指优先级越高,越有可能先执行,但只是建议先执行,具体什么时候执行由系统决定。

在Thread类中定义了三种静态成员变量:

 - public final static int MIN_PRIORITY = 1; 
 - public final static int NORM_PRIORITY = 5; 
 - public final static int MAX_PRIORITY = 10;

也就是线程优先级的取值范围是1-10;

public class Prio
{
    public static void main(String[] args)
    {
    	MyThread t1 = new MyThread();
        Thread p1 = new Thread(t1,"线程t1");
        MyThread t2 = new MyThread();
        Thread p2 = new Thread(t2,"线程t2");
        
        p1.setPriority(Thread.MIN_PRIORITY);    //设置优先级  1
        p2.setPriority(Thread.MAX_PRIORITY);    //设置优先级  10
       	System.out.println(Thread.currentThread().getPriority());  //主线程main优先级为5
    }
}
  • sleep() 线程休眠 不会释放锁
    Thread.sleep(millisec) 方法会休眠当前正在执行的线程,其他线程不受影响,millisec 单位为毫秒。
    sleep() 可能会抛出 InterruptedException,因为当前线程sleep的时候,有可能被停止,这时就会抛出 InterruptedException。
    线程休眠会立即交出CPU,但是不会释放锁。
public void run() {
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
  • join() 线程强制加入 会释放锁
    线程强制加入,强制加入的线程运行完毕后才会让出资源。
    如:主线程(或者某个线程)中若调用了子线程(或者是另外一个线程)的join()方法就必须得等该子线程run()方法结束,主线程才能继续执行
      join()方法只是对Object提供的wait()做了一层包装而已。( join在内部使用wait()方法进行等待 ),执行wait(long)方法后,当前线程的锁会被释放,其他线程就可以调用此线程中的同步方法了。
public class JoinDemo {
    public static void main(String[] args) {
        TestSleep s = new TestSleep();
        Thread t1 = new Thread(s,"线程t1"); //新建
        t1.start(); //就绪
        //cpu调度 运行
        for (int i=0; i<10; i++) {
            if(6 == i) {
               try {
                   t1.join(); //main 阻塞
               }
               catch(InterruptedException e) {
                   e.printStackTrace();
               }
            }
            System.out.println(Thread.currentThread().getName() +" " +i);
        }
    }
}
class TestSleep implements Runnable{
    public void run(){
        for(int i = 0; i < 6; i++){
            System.out.println(Thread.currentThread().getName() +" i : "+ i +" Join...");
        }
    }
}

输出结果:
在这里插入图片描述

  • yield() 线程让步 不会释放锁
    线程让步是指 暂停执行当前的线程对象,并执行其他线程,yield()方法会让当前线程交出CPU(不一定立即交出CPU),不会释放锁。
    yield()方法无法控制具体交出CPU的时间,并且yield()方法只能让拥有相同优先级的线程有获取CPU的机会。

    暂时让一会不是一直让,只让一会就不让了,具体调度要看CPU。
    不会释放锁。

public class YieldDemo {
    public static void main(String[] args) {
        TestSleep1 s = new TestSleep1();
        Thread t1 = new Thread(s,"线程t1"); //新建
        t1.start(); //就绪
        //cpu调度 运行
        for (int i=0; i<10; i++)
        {
            if(i == 4)
            {
                System.out.println("开始礼让:");
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName() +" " +i);
        }
    }
}
class TestSleep1 implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " i : " + i + " Yield...");
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值