多线程的内容

多线程

程序 一种编程语言写的指令集合体
进程一个程序的运行就是一种进程
线程是进程里的一个执行单元 一个进程中包含着多个线程

创建多线程

  1. 继承thread类 重写run方法 运行start方法
public class McxThread extends Thread {
    @Override
    public void run() {
        for (int i=0;i<40;i++){
            if(i%2==0){
                System.out.println(i);

            }
        }
    }


    public static void main(String[] args) {
        McxThread mcxThread = new McxThread();
        mcxThread.start();//作用:启动线程、调用run方法
        mcxThread.run();//直接调用run方法  线程没有被启动
       	//mcxThread.start();线程再次调用start不会在启动一个新的线程
        for (int i = 0; i < 40; i++) {
            if (i % 2 != 0) {
                System.out.println(i+"*******************");

            }
        }
    }
}
  1. 实现接口Runnable
public class McxThread1 implements Runnable {
    @Override
    public void run() {
        for (int i=0;i<40;i++) {
            if (i % 2 == 0) {
                System.out.println(i);

            }
        }
    }

    public static void main(String[] args) {
        //创建线程
        McxThread1 mthread=new McxThread1();
        //将线程放入thread类的有参构造方法里
        Thread thread=new Thread(mthread);
        //启动线程
        //运行线程的run方法
        thread.start();
        //因为在实现接口Runnable时 Thread thread=new Thread(target); 运行target.run()方法
    }
}

这俩个创建线程的方法比较

  • 相同点 public class Thread implements Runnable 这边都是重写了run方法 将逻辑写在run方法中
  • 俩这选择多选实现接口的方式
    * 继承方式的单一特性的局限性
    * 实现接口可以在数据上进行共享

Thread的相关方法

  • start方法启动线程并且运行run方法
  • run方法运行内部的方法
  • setName方法设置Thread的线程名
  • getName方法获取Thread的线程名
  • currentThread的获取当前线程
  • yield 释放cpu使用权
  • join a线程阻塞 b线程运行 运行结束后 a线程运行
  • stop 已过时 强制停止该线程
  • sleep 线程睡眠
  • isAlive 是否存活
线程的调度

首先线程是有优先级的 线程的优先级取决于对线程的priority的设置值
常量设置为
MIN_PRIORITY=1
NORM_PRIORITY=5
MAX_PRIORITY=10
Thread类的设置方位为
setPriority(int p)
getPriority
特别说明: 这里不代表着高优先级就先执行 只是抢占时间片的概率高一些

线程的生命周期

在这里插入图片描述

线程安全的问题的原因:
1. 操作共享信息有多个线程运行
2.  多线程操作同一个数据
解决线程安全的方法:
  1. 同步代码块
    synchronized(同步监视器){
  • 操作共享数据得代码
  • 共享数据:就是多个行程共同操作的变量
  • 同步监视器就是 锁 任何对象都可以作为锁 要求:多线程必须用同一个锁
    }
//1.继承thread类
public class McxThread extends Thread{
    private static Object object="";
    private static  Integer ticket=100;

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

    }


    public static void main(String[] args) {
        McxThread mcxThread = new McxThread();
        McxThread mcxThread1 = new McxThread();
        McxThread mcxThread2 = new McxThread();
        mcxThread.setName("一号口");
        mcxThread1.setName("二号口");
        mcxThread2.setName("三号口");
        mcxThread.start();
        mcxThread1.start();
        mcxThread2.start();

    }
}


//2.实现Runnable接口
public class McxThread implements Runnable{
    private Object object="";
    private Integer ticket=100;

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

    }


    public static void main(String[] args) {
        McxThread mcxThread = new McxThread();
       	Thread mcxThread0=new Thread(mcxThread);
       	Thread mcxThread1=new Thread(mcxThread);
       	Thread mcxThread2=new Thread(mcxThread);
        mcxThread0.setName("一号口");
        mcxThread1.setName("二号口");
        mcxThread2.setName("三号口");
        mcxThread0.start();
        mcxThread1.start();
        mcxThread2.start();

    }
}

运行结果如下:

二号口卖票100
二号口卖票99
二号口卖票98
二号口卖票97
二号口卖票96
二号口卖票95
二号口卖票94
二号口卖票93
二号口卖票92
二号口卖票91
二号口卖票90
二号口卖票89
二号口卖票88
二号口卖票87
二号口卖票86
二号口卖票85
二号口卖票84
二号口卖票83
二号口卖票82
二号口卖票81
二号口卖票80
二号口卖票79
二号口卖票78
二号口卖票77
二号口卖票76
二号口卖票75
二号口卖票74
二号口卖票73
二号口卖票72
二号口卖票71
二号口卖票70
二号口卖票69
二号口卖票68
二号口卖票67
二号口卖票66
二号口卖票65
二号口卖票64
二号口卖票63
二号口卖票62
二号口卖票61
二号口卖票60
二号口卖票59
二号口卖票58
二号口卖票57
二号口卖票56
三号口卖票55
三号口卖票54
三号口卖票53
三号口卖票52
三号口卖票51
三号口卖票50
三号口卖票49
三号口卖票48
三号口卖票47
三号口卖票46
三号口卖票45
三号口卖票44
三号口卖票43
三号口卖票42
三号口卖票41
三号口卖票40
三号口卖票39
三号口卖票38
三号口卖票37
三号口卖票36
三号口卖票35
三号口卖票34
一号口卖票33
一号口卖票32
一号口卖票31
一号口卖票30
一号口卖票29
一号口卖票28
一号口卖票27
一号口卖票26
一号口卖票25
一号口卖票24
一号口卖票23
一号口卖票22
一号口卖票21
一号口卖票20
一号口卖票19
一号口卖票18
一号口卖票17
一号口卖票16
一号口卖票15
一号口卖票14
一号口卖票13
一号口卖票12
一号口卖票11
一号口卖票10
一号口卖票9
一号口卖票8
一号口卖票7
一号口卖票6
一号口卖票5
一号口卖票4
一号口卖票3
一号口卖票2
一号口卖票1
  1. 同步方法
    就是进行操作共享数据的指令在一个方法中 可以直接定义为同步方法
    总结:
    同步方法也需要同步监视器 只不过不是显示监视器
    静态的同步方法的锁为:当前类本身
    非静态的同步方法的锁为:this
//1.继承thread类
public class McxThread extends Thread{
    private static  Integer ticket=100;

    @Override
    public void run() {
        while (true){
             show();
            }


    }

    private static synchronized void show() {
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "卖票" + ticket);
            ticket--;
        }
    }


    public static void main(String[] args) {
        McxThread mcxThread = new McxThread();
        McxThread mcxThread1 = new McxThread();
        McxThread mcxThread2 = new McxThread();
        mcxThread.setName("一号口");
        mcxThread1.setName("二号口");
        mcxThread2.setName("三号口");
        mcxThread.start();
        mcxThread1.start();
        mcxThread2.start();

    }
}
//2.实现Runnable接口
public class McxThread extends Thread{
    private  Integer ticket=100;

    @Override
    public void run() {
        while (true){
             show();
            }


    }

    private synchronized void show() {
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "卖票" + ticket);
            ticket--;
        }
    }


    public static void main(String[] args) {
  		McxThread mcxThread = new McxThread();
       	Thread mcxThread0=new Thread(mcxThread);
       	Thread mcxThread1=new Thread(mcxThread);
       	Thread mcxThread2=new Thread(mcxThread);
        mcxThread0.setName("一号口");
        mcxThread1.setName("二号口");
        mcxThread2.setName("三号口");
        mcxThread0.start();
        mcxThread1.start();
        mcxThread2.start();

    }
}

运行结果如下

一号口卖票100
一号口卖票99
一号口卖票98
一号口卖票97
一号口卖票96
一号口卖票95
一号口卖票94
一号口卖票93
一号口卖票92
一号口卖票91
一号口卖票90
一号口卖票89
一号口卖票88
三号口卖票87
三号口卖票86
三号口卖票85
三号口卖票84
三号口卖票83
三号口卖票82
三号口卖票81
三号口卖票80
三号口卖票79
三号口卖票78
三号口卖票77
三号口卖票76
三号口卖票75
三号口卖票74
三号口卖票73
三号口卖票72
三号口卖票71
三号口卖票70
三号口卖票69
三号口卖票68
三号口卖票67
三号口卖票66
三号口卖票65
三号口卖票64
三号口卖票63
三号口卖票62
三号口卖票61
三号口卖票60
三号口卖票59
三号口卖票58
三号口卖票57
三号口卖票56
三号口卖票55
三号口卖票54
三号口卖票53
三号口卖票52
三号口卖票51
三号口卖票50
三号口卖票49
三号口卖票48
三号口卖票47
三号口卖票46
三号口卖票45
三号口卖票44
三号口卖票43
三号口卖票42
三号口卖票41
三号口卖票40
三号口卖票39
三号口卖票38
三号口卖票37
三号口卖票36
三号口卖票35
三号口卖票34
三号口卖票33
三号口卖票32
三号口卖票31
三号口卖票30
三号口卖票29
三号口卖票28
三号口卖票27
三号口卖票26
三号口卖票25
三号口卖票24
三号口卖票23
三号口卖票22
三号口卖票21
三号口卖票20
三号口卖票19
三号口卖票18
三号口卖票17
三号口卖票16
三号口卖票15
三号口卖票14
三号口卖票13
三号口卖票12
三号口卖票11
三号口卖票10
三号口卖票9
三号口卖票8
三号口卖票7
三号口卖票6
三号口卖票5
三号口卖票4
三号口卖票3
三号口卖票2
三号口卖票1

  1. 同步锁lock(ReentrantLock)
    同步方法/同步代码块 与同步锁的区别
    自动释放线程 而同步锁需要手动释放 lock.unlock
public class McxThread3 extends Thread{
    private static  Integer ticket=100;
    private static   ReentrantLock lock=new ReentrantLock();
    @Override
    public void run() {
        while (true){
            //启动同步锁
            lock.lock();
            show();
            //关闭同步锁
            lock.unlock();
            }


    }

    private static void show() {
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "卖票" + ticket);
            ticket--;
        }
    }


    public static void main(String[] args) {
        McxThread3 mcxThread = new McxThread3();
        McxThread3 mcxThread1 = new McxThread3();
        McxThread3 mcxThread2 = new McxThread3();
        mcxThread.setName("一号口");
        mcxThread1.setName("二号口");
        mcxThread2.setName("三号口");
        mcxThread.start();
        mcxThread1.start();
        mcxThread2.start();
    }
}

死锁

不同的线程占着对方所需要的同步监视器即锁 都在等待对方放开自己所需要的锁 从而形成的死锁
出现死锁后 不会出现异常 不会出现错误 线程都被阻塞 无法继续

解决方法
  • 不要进行嵌套操作
  • 尽量避免同步资源的定义
  • 专门的算法

wait(),noitfy(),notifyAll()三个方法必须在同步代码块或者同步方法中
wait(),noitfy(),notifyAll()三个方法必须在同步代码块或者同步方法中的同步监视器
wait(),noitfy(),notifyAll()三个方法都是object类中

面试题

wait()与sleep()的区别

  • 相同点 俩者都是将线程进行阻塞
  • 不同点
    1. 使用的位置不同 sleep()是Thread类声明 wait()是在Object类
    2. sleep()可以在任何情景下使用 wait() 只能在同步代码块或者同步方法里使用
    3. sleep()线程不释放锁 而wait()线程是释放锁的

jdk5.0发布的俩种创建线程方式

  • 实现接口Callable创建线程
package com.mcx.test.demo;

import sun.print.SunMinMaxPage;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @Author MCX
 * @Version 1.0
 **/
//1.创建一个类实现接口Callable
public class CallThread implements Callable {
    //2.重写方法call
    @Override
    public Object call() throws Exception {
        int sum=0;
        for (int i = 0; i < 100; i++) {
            System.out.println("i====="+i);
            sum+=i;
        }
        return sum;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //3.新建实现接口的类
        CallThread callThread=new CallThread();
        //4.Callable实现类作为对象传到FutureTask构造器里
        FutureTask<Integer> futureTask=new FutureTask<>(callThread);
        //5.将futureTask作为参数放入Thread方法中,执行start方法  运行线程
        new Thread(futureTask).start();
        //6.获取线程的返回值
        Integer integer = futureTask.get();
    }
}

  • 线程池
package com.mcx.test.demo;

import java.util.concurrent.*;

/**
 * @Author MCX
 * @Version 1.0
 *
 *
 * 线程池
 * (1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
 *
 * (2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
 *
 * (3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
 **/

public class Threads {


    public static void main(String[] args) {
        //创建固定的线程池
        ExecutorService service=Executors.newFixedThreadPool(15);
        //设置线程池属性
        ThreadPoolExecutor service1= (ThreadPoolExecutor) service;
        service1.setCorePoolSize(15);//设置核心池的大小
        service1.setMaximumPoolSize(10);//最大线程数
        service1.setKeepAliveTime(10,TimeUnit.SECONDS);//线程没有任务时最大存活时长
        //3.执行实现Runnable接口RunThread线程  执行实现Callable接口Callable线程
        service.execute(new RunThread());

        service.submit(new CallThread());
        //4.关闭线程池
        service.shutdown();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值