多线程入门


<font color=#999AAA


提示:以下是本篇文章正文内容,下面案例可供参考

一、多线程是什么?

其实多线程在生活中,非常常见,比如我们平时去上厕所的时候总不能少了一样非常重要的东西,手机!(卫生纸也重要),那么我们一边玩手机一边上厕所就可以简单的理解为一个多线程。现实中有很多这种例子,看起来都在同时做,但本质上我们大脑同一时间只做了同一件事,只是切换的比较快。在这里插入图片描述

二、进程和线程

首先,要理解进程与线程的定义分别是什么。进程是并发执行的程序在执行过程中分配和管理资源的基本单位。线程是进程的一个执行单元,是比进程还要小的独立运行的基本单位。一个程序至少有一个进程,一个进程至少有一个线程。
根本区别:进程是资源分配最小单位,线程是程序执行的最小单位。 计算机在执行程序时,会为程序创建相应的进程,进行资源分配时,是以进程为单位进行相应的分配。每个进程都有相应的线程,在执行程序时,实际上是执行相应的一系列线程。

三、线程创建的三种方式

1. 继承Thread类

package wx.Thread;

/**
 * 创建线程的方法
 * 1.继承Thread类
 * 重写run方法
 * 调用start启动线程
 *
 *  结果分析
 *  执行结果中,两个线程交替执行
 *  结果交替输出,需要数据足够多的时候才会出现这种情况
 *  线程不一定立即执行,由cpu暗排调度
 */
public class ThreadDemo1 extends Thread{
//    run方法

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println( "我在看代码"+i);
        }
    }

//    主线程
public static void main(String[] args) {
//        创建线程对象
    ThreadDemo1 threadDemo1=new ThreadDemo1();
    threadDemo1.start();


    for (int i = 0; i < 2000; i++) {
        System.out.println("我在主线程"+i);
    }
    
}
}

2.实现Runnable接口

好处:避免单继承的局限,一个线程可以被多个对象使用

package wx.Thread;

/**
 *1.实现Runnable创建线程
 *2.重写run方法
 * 3.创建线程对象,执行线程需要丢如runnable实现类,启动start方法
 */

public class ThreadDemo2 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println( "我在看代码"+i);
        }
    }

    //    主线程
    public static void main(String[] args) {
//        创建runnable实现类
        ThreadDemo2 threadDemo2=new ThreadDemo2();
//       创建线程对象  代理
        Thread thread=new Thread(threadDemo2);
        thread.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("我在主线程"+i);
        }

    }
}

一般情况下,都推荐使用这种方式

三 . 实现Callable接口

三、线程的五大状态

(1)新建状态:即单纯地创建一个线程,创建线程有三种方式。

(2)就绪状态:在创建了线程之后,调用Thread类的start()方法来启动一个线程,即表示线程进入就绪状态!

(3)运行状态:当线程获得CPU时间,线程才从就绪状态进入到运行状态!

(4)阻塞状态:线程进入运行状态后,可能由于多种原因让线程进入阻塞状态,如:调用sleep()方法让线程睡眠,调用wait()方法让线程等待,调用join()方法、suspend()方法(它现已被弃用!)以及阻塞式IO方法。

(5)死亡状态:run()方法的正常退出就让线程进入到死亡状态,还有当一个异常未被捕获而终止了run()方法的执行也将进入到死亡状态!

四、线程休眠sleep和wait的异同

相同点:一旦执行方法以后,都会使得当前的进程进入阻塞状态。

不同点:
1.两个方法声明的位置不同,Thread类中声明sleep,Object类中声明wait。
2.调用的要求不同,sleep可以在任何需要的场景下调用,wait必须使用在同步代码块或者同步方法中。
3.关于是否释放同步监视器,如果两个方法都使用在同步代码块或同步方法中,sleep不会释放,wait会释放。

五、join强制加入方法

join方法会强行让正在执行的线程进入阻塞状态,优先执行自己,就像人民币玩家。

package wx.Thread;

public class JoinDemo1 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("线程VIP来了"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
//        启动线程
        JoinDemo1 joinDemo1=new JoinDemo1();
        Thread thread=new Thread(joinDemo1);
        thread.start();

//        主线程
        for (int i = 0; i < 500; i++) {
            if (i == 200) {
                thread.join();
            }
            System.out.println("main"+i);
        }
    }


}

六、锁

为什么要加锁?
多线程保证线程安全就是让多个线程执行的情况和单线程一样,读的时候是不影响线程安全的,但如果对数据操作,增加或者删除,几个线程同时进行,就会发生删多或者增加多的情况,这时候为了保证线程安全,就可以加对象锁

Synchronized锁

方式一:同步代码块

使用同步监视器(锁)
Synchronized(同步监视器){
//需要被同步的代码
}

方式二:同步方法

将同步代码块提取出来成为一个方法,用synchronized关键字修饰此方法。
}

代码演示(买火车票)

package wx.Thread;

/**
 * 多个线程操作同一个对象
 * 买火车票的例子
 *
 *
 * 结果总结:线程不安全
 */
public class ThreadDemo3 implements Runnable {
//票数
    private int ticketNums=10;

    @Override
//    synchronized线程同步
    public synchronized void run() {
        while (true){

            if (ticketNums<=0){
                break;
            }
//            延迟模型
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"拿到了"+ticketNums+"票");
            ticketNums--;
        }

    }

    public static void main(String[] args) {
//        创建runnable实现类
        ThreadDemo3 threadDemo3=new ThreadDemo3();

        new Thread(threadDemo3,"小明").start();
        new Thread(threadDemo3,"小黄").start();
        new Thread(threadDemo3,"花鸟名").start();

    }
}

代码演示(两个人同时取钱)

package wx.Thread.ThreadShiyan.demo3;

public class Account {
    int money; //余额
    String name ;//卡名

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}



package wx.Thread.ThreadShiyan.demo3;
// 取钱线程
public class getMoney implements Runnable {
//    账户
        Account account;

    public void setAccount(Account account) {
        this.account = account;
    }

    private int getMoney;

    public void setGetMoney(int getMoney) {
        this.getMoney = getMoney;
    }
//    取钱 同步方法
    @Override
    public synchronized void run() {
        if ((account.money-getMoney)>=0){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.money=account.money-getMoney;
            System.out.println(Thread.currentThread().getName()+"取了"+getMoney+"元");
            System.out.println("账户余额"+account.money);
        }else{
            System.out.println("账户余额不足");
        }
    }
    //    取钱 同步代码块
//    @Override
//    public  void run() {
//    synchronized (account){
//        if ((account.money-getMoney)>=0){
//            account.money=account.money-getMoney;
//            System.out.println(Thread.currentThread().getName()+"取了"+getMoney+"元");
//            System.out.println("账户余额"+account.money);
//        }else{
//            System.out.println("账户余额不足");
//        }
//    }
//
//    }
}






package wx.Thread.ThreadShiyan.demo3;

public class test {
    public static void main(String[] args)  {
//        创建一个账户
        Account account=new Account(1000,"wx");
        getMoney getMoney=new getMoney();
        getMoney.setGetMoney(600);
        getMoney.setAccount(account);
        new Thread(getMoney,"妻子").start();
        new Thread(getMoney,"张三").start();

    }
}


JDK5.0新增的lock锁方法

代码演示

package wx.Thread;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {
    public static void main(String[] args) {
        TestLock1 testLock1=new TestLock1();
        new Thread(testLock1,"小明").start();
        new Thread(testLock1,"小黄").start();
        new Thread(testLock1,"小兰").start();

    }
}
class TestLock1 implements Runnable{
//    定义锁
   private ReentrantLock lock=new ReentrantLock();
    int tickets=10;
    @Override
    public void run() {
        while (true){
            try {
                lock.lock();//加锁
                if (tickets>=0){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+tickets--);
                }else{
                    break;
                }
            }finally {
                lock.unlock();//解锁
            }

        }
    }
}

Synchronized与lock的异同?

1.相同
二者都可以解决线程安全问题
2.不同
synchronized机制在执行完相应的代码逻辑以后,自动的释放同步监视器
lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())(同时以为着lock的方式更为灵活)

死锁解决办法

1.减少同步共享变量

2.采用专门的算法,多个线程之间规定先后执行的顺序,规避死锁问题。

3.减少锁的嵌套。

六、线程池

创建方式

1)newCachedThreadPool创建一个可缓存线程池

2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数。

3)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

4)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务。

简单代码演示

package wx.Thread.ThreadPool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 测试线程池
 *
 */
public class TestPool {
    public static void main(String[] args) {

//        创建线程池
        ExecutorService executorService= Executors.newFixedThreadPool(10);
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());

//        关闭
        executorService.shutdown();

    }
}

//线程
class MyThread implements Runnable{

    @Override
    public void run() {

            System.out.println( Thread.currentThread().getName());
    }
}





package wx.Thread.ThreadPool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 测试线程池
 *
 */
public class TestPool {
    public static void main(String[] args) {

//        创建线程池
        ExecutorService executorService= Executors.newFixedThreadPool(10);
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());

//        关闭
        executorService.shutdown();

    }
}

//线程
class MyThread implements Runnable{

    @Override
    public void run() {

            System.out.println( Thread.currentThread().getName());
    }
}

执行过程

在这里插入图片描述


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林觉眠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值