多线程

多线程

一.进程与线程

1.概述

(1)进程

正在运行的程序,我们的电脑上可以有多个进程,在某一时间点上单核CPU只能执行一个进程,CPU可以在多个进程之间可以进行高速切换,人耳和眼睛是感觉不出来的
多进程可以提高CPU的利用率
进程是拥有资源的基本单位

(2)线程

线程:线程需要依赖于进程,进程开启后他会执行很多的任务,把每个任务称之为线程
我们把程序的执行路径只有一条称之为单线程环境,把程序的执行有多条路径,称之为多线程环境
线程是CPU调度资源的基本单位
多线程支持并发和并行
线程的作用不是提高执行速度,而是为了提高应用程序的使用率。
jvm是多线程,至少有俩个线程,一个线程就是主线程,还有一个垃圾回收线程

二.并发与并行

1.概述

(1)并发

指应用能够交替执行不同的任务,并发可以在单处理器和多处理器系统中都存在(每个小时间片执行一个操作,多个操作快速切换执行)
目标:是充分利用处理器的每一个核,达到最高的处理效果

(2)并行

指应用能够同时执行多个不同的任务,并行在多处理器系统中存在

三.实现多线程

1.开启线程的三种方式

方式一

(1)定义一个类,继承Thread类

(2)重写Thread类中的run方法;run方法是需要线程来执行的代码,一般是耗时的

(3)创建我们写的类的对象

(4)开启线程

注意

开启线程不是调用run()方法,调用run()方法,就是你使用了一个对象让这个方法执行了,线程并没有开启;
正确开启线程的方式是调用start()方法开启线程,由线程去调用run()方法.
同一个线程不要多次开启,会抛异常

public static void main(String[] args) {
 MyThread myThreadnew =new MyThread();
        Thread th1 =new Thread(myThreadnew);
        th1.start();
//或者可以写成new MyThread().start();
}
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("线程执行了");
    }
}
方式二(实现接口时还可以继承其他类,灵活性强)

(1)创建一个类,实现Runable接口,重写该接口的run方法

(2)创建Thread类对象,将Runable的子类对象传递进来

(3)调用start()方法开启线程

代码演示:

public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.setName("线程A");
        thread.start();
    }

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name+"任务执行了");
    }
}

Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。

方式三

(1)创建一个类实现Callable 接口

(2)创建一个FutureTask类将Callable接口的子类对象作为参数传进去

(3)创建Thread类,将FutureTask对象作为参数传进去

(4)开启线程

特点

实现 Callable 接口。 相较于实现 Runnable 接口的方式,方法可以有返回值,并且可以抛出异常。
线程执行完后可以获取线程运算完的结果
执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。 FutureTask 是 Future 接口的实现类
代码演示:

//主程序
public class MyCallable implements Callable<Integer> {
MyCallable myCallable = new MyCallable();
        FutureTask<Integer> task = new FutureTask<>(myCallable);
        Thread thread = new Thread(task);
        thread.start();
        //线程执行完之后,可以获取结果
        Integer integer = task.get();
        System.out.println(integer);
}
 //MyCallable类      
public class MyCallable implements Callable<Integer> {
    //call方法就是线程要执行的方法
    @Override
    public Integer call() throws Exception {
        System.out.println("线程执行了");
        int sum=0;
        for (int i = 1; i <= 100; i++) {
            sum+=i;
        }
        return sum;
    }
}

2.几种常用的方法

this.getName()//获取线程名称

thread.setName("哈哈");//设置线程名称

Thread.currentThread().getName()//获取当前线程的名字

thread.getName();//获取主线程名字

thread.sleep(100)//让系统在指定时间段休眠,让线程处于一种阻塞状态

thread.stop();//停止一个线程(废弃方法)

thread.interrupt() //打断线程的一个阻塞状态

thread.join() //等待该线程终止。
//串行: 多线程按顺序自行(将并行改为串行)
//在线程开启之后再调用

thread.getPriority(); //返回线程的优先级。

thread.setPriority(int newPriority); //更改线程的优先级。

thread.yield(): //暂停当前正在执行的线程对象,并执行其他线程。
//多线程礼让,你一下我一下

setDaemon(true)//在线程开启之前可以设为守护线程,主线程(用户线程)结束,守护线程就结束

3.线程优先级

线程调度模型有俩种,分别是分时调度模型和抢占式调度
java使用的是抢占式调度,如果说多个线程的优先级一样,那么线程的执行就会随机抢占,

4.Java用户线程和守护线程

(1)用户线程和守护线程的区别

户线程和守护线程的区别
用户线程和守护线程都是线程,区别是Java虚拟机在所有用户线程dead后,程序就会结束。而不管是否还有守护线程还在运行,若守护线程还在运行,则会马上结束。

(2)用户线程和守护线程的适用场景

由两者的区别及dead时间点可知,守护线程不适合用于输入输出或计算等操作,因为用户线程执行完毕,程序就dead了,适用于辅助用户线程的场景,如JVM的垃圾回收,内存管理都是守护线程,还有就是在做数据库应用的时候,使用的数据库连接池,连接池本身也包含着很多后台线程,监听连接个数、超时时间、状态等。

(3)创建守护线程

调用线程对象的方法setDaemon(true),设置线程为守护线程。

注意
1)thread.setDaemon(true)必须在thread.start()之前设置。

2)在Daemon线程中产生的新线程也是Daemon的。

3)不是所有的应用都可以分配给Daemon线程来进行服务,比如读写操作或者计算逻辑,因为Daemon Thread还没来得及进行操作,虚拟机可能已经退出了。

5.数据安全问题

(1)造成原因

1.多线程环境
2.多个线程在并发操作共享数据
3.有多条语句在操作这个共享数据

(2)解决办法

a.可以使用同步代码块来解决线程安全问题

synchronized(){      //锁,任意对象,放置可能出现线程安全的方法

}//多个线程要共享一把锁

b.可以使用同步代码块来解决线程安全问题

方法上加有synchronized关键字称为同步方法

注意同步代码块使用任意对象同步方法使用的锁对象不是任意对象,他用的锁是this静态同步方法使用的锁对象不是任意对象,他用的锁是当前类的字节码类型

(3)死锁问题

如果出现了同步嵌套,就容易产生死锁问题
死锁是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象

代码演示

public class new1 {
    public static void main(String[] args) {
        test t1 = new test(true);
        test t2 = new test(false);
        t1.start();
        t2.start();
    }
}
-------------------------------------------------------------
package org.westos.demo10;

public interface ObjectUntils {
    Object objA =new Object();
    Object objB =new Object();
}

-------------------------------------------------------------
public class test extends Thread {
    boolean flag;
    public  test(boolean flag){
        this.flag=flag;
    }
    public void run(){
      if (flag){
        synchronized (ObjectUntils.objA){
           System.out.println("objA:true我进来了");
        synchronized (ObjectUntils.objB){
           System.out.println("objB:true我也进来了");
                }
            }
        }
     else{
        synchronized (ObjectUntils.objB){
            System.out.println("objB:false我也进来了");
        synchronized (ObjectUntils.objA){
            System.out.println("objA:false我也进来了");
                 }
             }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值